openapi: 3.1.0
info:
  title: API do Dashboard Mágico
  version: 1.0.0
  description: |-
    ¡Tú que eres dev, diviértete! ✨

    > **Índice de la documentación** — accede al índice completo en [https://docs.dashboards.kobana.com.br/llms.txt](https://docs.dashboards.kobana.com.br/llms.txt). Usa este archivo para descubrir todas las páginas disponibles antes de explorar.

    > **Atención a las versiones de la API** — estás en la documentación de la **v1.0** de la API de Dashboard Mágico, que cubre la organización, los usuarios del portal y el equipo del dashboard. Recursos como **Pagos, Transferencias, Extracto y Recepción por Pix** están disponibles en otras APIs de Kobana — usa el selector de producto en el menú superior para acceder.

    ## Formato

    La API solo acepta `JSON`. Todas las solicitudes deben usar `Content-Type: application/json`. Todas las respuestas usan `snake_case`.

    | Tipo de Campo | Formato |
    | :--- | :--- |
    | **DateTime** | Formato [ISO8601](https://es.wikipedia.org/wiki/ISO_8601). Ejemplos — Fecha: `2026-01-24`. Fecha y hora: `2026-01-24T10:07Z` |
    | **UUID** | Identificadores de recursos en formato UUID v4 |

    ## Convenciones

    Convenciones usadas en esta documentación:

    | Convención | Descripción |
    | :--- | :--- |
    | **`:variable`** | Nombre de variable que debe sustituirse en una URL. |
    | **`#{variable}`** | Nombre de variable que debe sustituirse por valores de tu cuenta. |
    | **`...`** | Contenido de la respuesta truncado para facilitar la lectura. |
    | **`$KOBANA_TOKEN`** | Token de acceso. Para pruebas en línea de comandos, expórtalo: `export KOBANA_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxx` y pega los comandos de la documentación en la terminal. |

    ## Códigos de Retorno

    La API devuelve códigos HTTP estándar:

    | | Código | Descripción |
    | :--- | :--- | :--- |
    | ✅ | **200 OK** | Solicitud exitosa con cuerpo de respuesta. |
    | ✅ | **201 Created** | Recurso creado con éxito. |
    | ✅ | **204 No Content** | Solicitud exitosa sin cuerpo de respuesta. |
    | ❌ | **400 Bad Request** | Solicitud inválida, generalmente contenido mal formado. |
    | ❌ | **401 Unauthorized** | Token de acceso ausente o inválido. |
    | ❌ | **403 Forbidden** | Acceso a la API bloqueado o usuario sin permiso. |
    | ❌ | **404 Not Found** | El recurso no existe. |
    | ❌ | **422 Unprocessable Entity** | Solicitud válida, pero los datos enviados no lo son. |
    | ❌ | **429 Too Many Requests** | Límite de solicitudes alcanzado. |
    | ❌ | **500 Internal Server Error** | Error interno de procesamiento. Consulta el [estado de los servidores](https://status.kobana.com.br). |

    ## ID de las Solicitudes (Request ID)

    Cada solicitud tiene un identificador asociado, disponible en la cabecera `Request-Id` de la respuesta. Este valor ayuda en la depuración y auditoría — las solicitudes y sus IDs pueden consultarse en el panel del sistema. El registro de solicitudes está disponible por **30 días**. Al abrir un ticket de soporte sobre una solicitud específica, informa el `Request-Id` para acelerar la investigación.

    ## Seguridad

    La API de Kobana usa certificados **SSL 2048 bits**. Toda solicitud debe hacerse vía **HTTPS** — las llamadas al puerto 80 son redirigidas al 443.

    Los clientes deben soportar `TLSv1.2` o `TLSv1.3` con una de las cifras: `TLS_AES_128_GCM_SHA256`, `TLS_AES_256_GCM_SHA384`, `TLS_CHACHA20_POLY1305_SHA256`, `ECDHE-RSA-AES128-GCM-SHA256`, `ECDHE-RSA-AES128-SHA256`, `ECDHE-RSA-AES256-GCM-SHA384`, `ECDHE-RSA-CHACHA20-POLY1305`, `ECDHE-RSA-AES256-SHA384`. `TLSv1` y `TLSv1.1` no son soportados.

    ## Caché HTTP

    Usa las cabeceras HTTP de caché para reducir carga y ganar velocidad. La mayoría de las respuestas incluye `ETag` y/o `Last-Modified` — guarda estos valores y reenvíalos en las siguientes solicitudes vía `If-None-Match` e `If-Modified-Since`. Si el recurso no cambió, la respuesta será `304 Not Modified`, sin cuerpo y sin reprocesamiento. Más información: [HTTP Cache Docs](http://www.mnot.net/cache_docs/).

    ## Manejo de Errores

    Los errores 5xx indican fallas del servidor: **500 Internal Server Error** (aplicación indisponible), **502 Bad Gateway**, **503 Service Unavailable** y **504 Gateway Timeout** (fallas puntuales de infraestructura). Tu aplicación debe identificar estos códigos y reintentar la solicitud después de algunos minutos con backoff. Estado de los servidores: [https://status.kobana.com.br](https://status.kobana.com.br).
  license:
    name: Proprietário — Kobana
    url: https://kobana.com.br
servers:
  - url: https://api.dashboards.kobana.com.br
    description: Producción. Sustituido en tiempo de ejecución cuando `API_V1_PUBLIC_URL` está definido.
  - url: https://api.dashboards.sandbox.kobana.com.br
    description: Sandbox — entorno de pruebas aislado de producción.
components:
  schemas:
    ApiV1Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              description: Código de error estable. Usa este campo para tratar el error programáticamente — nunca hagas parse del `message`.
              example: invalid_token
            message:
              type: string
              description: Mensaje legible para humanos. Nunca incluye datos del usuario verbatim.
              example: Cabeçalho Authorization ausente.
            details:
              description: "Payload opcional específico del error (ej.: `{ required, granted }` en `insufficient_scope`)."
          required:
            - code
            - message
          description: Envelope de error. Presente en toda respuesta 4xx y 5xx.
      required:
        - error
    PaginationMeta:
      type: object
      properties:
        total:
          type: integer
          description: Total de ítems en todas las páginas.
        page:
          type: integer
          description: Página actual (comienza en 1).
        per_page:
          type: integer
          description: Ítems por página.
        total_pages:
          type: integer
          description: Total de páginas.
      required:
        - total
        - page
        - per_page
        - total_pages
    DeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    OrganizationPersonV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          description: Razón social o nombre de visualización.
        nickname:
          type:
            - string
            - "null"
        legal_name:
          type:
            - string
            - "null"
        document_type:
          type:
            - string
            - "null"
          enum:
            - cpf
            - cnpj
          description: "Tipo de documento: `cpf` o `cnpj`."
        document_number:
          type:
            - string
            - "null"
          description: Número del documento (solo dígitos).
        kind:
          type:
            - string
            - "null"
          enum:
            - individual
            - company
        birthday:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
        addresses:
          description: Lista de direcciones.
        phones:
          description: Lista de teléfonos de contacto.
        emails:
          description: Lista de correos de contacto.
        websites: {}
        tags:
          type:
            - array
            - "null"
          items:
            type: string
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        type:
          type: string
        parent_id:
          type:
            - string
            - "null"
          format: uuid
        external_id:
          type:
            - string
            - "null"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - name
    OrganizationV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público estable del recurso.
        external_id:
          type:
            - string
            - "null"
          description: Identificador externo de la organización en el sistema de Kobana.
        status:
          type: string
          description: "Estado de la organización (ej.: `active`)."
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios. Las claves internas (`apiKeys`, `encryptionKey`, `secrets`) se eliminan antes de la respuesta.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor). A diferencia de `metadata`, no se sanitiza — no almacene secretos aquí.
        person:
          allOf:
            - $ref: "#/components/schemas/OrganizationPersonV1"
            - description: Datos registrales de la organización (nombre, documento, contactos, direcciones). Siempre incluido.
      required:
        - id
        - public_id
        - external_id
        - status
        - created_at
        - updated_at
        - person
    OrganizationResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/OrganizationV1"
      required:
        - data
    OrganizationUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre de visualización de la organización.
        email:
          type: string
          format: email
          description: Correo de contacto principal de la organización.
        phone:
          type: string
          description: Teléfono de contacto principal de la organización.
        addresses:
          type: array
          items: {}
          description: Lista de direcciones de la organización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    MeUserV1:
      type:
        - object
        - "null"
      properties:
        id:
          type: string
          format: uuid
          description: Identificador del miembro del dashboard.
        name:
          type:
            - string
            - "null"
          description: Nombre del miembro.
        email:
          type: string
          description: Correo del miembro.
      required:
        - id
        - name
        - email
      description: Persona dueña del token; `null` cuando el token no pertenece a una persona (token de máquina).
    MeOrganizationV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Identificador de la organización a la que pertenece el token.
        name:
          type:
            - string
            - "null"
          description: Nombre de visualización de la organización.
        external_id:
          type:
            - string
            - "null"
          description: Identificador externo de la organización en el sistema de Kobana.
      required:
        - id
        - name
        - external_id
    MeTokenV1:
      type: object
      properties:
        type:
          type: string
          enum:
            - oauth
            - api_key
          description: "`oauth` (flujo de autorización) o `api_key` (token personal o de máquina)."
        scopes:
          type: array
          items:
            type: string
          description: Scopes concedidos al token.
        access_level:
          type: string
          enum:
            - read
            - write
            - all
          description: "Nivel de acceso más alto concedido: `read`, `write` o `all`."
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Expiración del token (ISO 8601), o `null` cuando se desconoce.
      required:
        - type
        - scopes
        - access_level
        - expires_at
    MeV1:
      type: object
      properties:
        user:
          $ref: "#/components/schemas/MeUserV1"
        organization:
          $ref: "#/components/schemas/MeOrganizationV1"
        token:
          $ref: "#/components/schemas/MeTokenV1"
      required:
        - user
        - organization
        - token
    MeResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/MeV1"
      required:
        - data
    PortalUserV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type:
            - string
            - "null"
          format: uuid
          description: Identificador público de la cuenta Kobana vinculada al usuario, cuando la hay.
        email:
          type: string
        status:
          type: string
          enum:
            - active
            - pending_verification
            - pending_invitation
            - suspended
            - locked
          description: "`pending_invitation` (invitación enviada), `pending_verification` (registro esperando la confirmación del correo), `active`, `suspended` o `locked` (bloqueado por intentos de acceso)."
        sso_only:
          type: boolean
        external_id:
          type:
            - string
            - "null"
          description: Identificador del usuario en su sistema de origen (también usado en el SSO). Único por workspace.
        tenant_id:
          type:
            - string
            - "null"
          description: "ID del titular: el identificador con el que el portal empareja los registros de las entidades que este usuario ve. Varios usuarios pueden compartir el mismo `tenant_id`."
        email_verified_at:
          type:
            - string
            - "null"
          format: date-time
        last_login_at:
          type:
            - string
            - "null"
          format: date-time
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_via:
          type:
            - string
            - "null"
          enum:
            - dashboard
            - import
            - api
            - mcp
            - cli
            - other
          description: Canal por el cual se creó el registro (dashboard, import, api, mcp, cli, other). En las llamadas a la API, viene de la cabecera `X-Request-Source`.
        created_via_other:
          type:
            - string
            - "null"
          description: Nombre de la aplicación que creó el registro cuando `created_via` es `other` (cabecera `X-Request-Source-Other`).
        created_by_email:
          type:
            - string
            - "null"
          description: Correo electrónico del usuario que creó el registro.
        updated_via:
          type:
            - string
            - "null"
          enum:
            - dashboard
            - import
            - api
            - mcp
            - cli
            - other
          description: Canal de la última actualización del registro.
        updated_via_other:
          type:
            - string
            - "null"
          description: Nombre de la aplicación de la última actualización cuando `updated_via` es `other` (cabecera `X-Request-Source-Other`).
        updated_by_email:
          type:
            - string
            - "null"
          description: Correo electrónico del usuario que hizo la última actualización.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        name:
          type:
            - string
            - "null"
          description: Nombre del perfil de contacto vinculado, cuando lo hay.
      required:
        - id
        - public_id
        - email
        - status
        - sso_only
        - external_id
        - tenant_id
        - email_verified_at
        - last_login_at
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    PortalUserListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PortalUserV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PortalUserResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalUserV1"
      required:
        - data
    PortalUserCreateRequest:
      type: object
      properties:
        email:
          type: string
          description: Correo del usuario (obligatorio). Único por workspace, sin distinguir mayúsculas.
        tenant_id:
          type:
            - string
            - "null"
          description: ID del titular de los registros que el usuario verá en el portal. Envíe `null` para limpiarlo.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        sso_only:
          type: boolean
          description: Cuando es `true`, el usuario solo entra por el SSO.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por la organización (clave/valor).
      required:
        - email
    PortalUserUpdateRequest:
      type: object
      properties:
        email:
          type: string
          description: Correo del usuario (obligatorio). Único por workspace, sin distinguir mayúsculas.
        tenant_id:
          type:
            - string
            - "null"
          description: ID del titular de los registros que el usuario verá en el portal. Envíe `null` para limpiarlo.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        sso_only:
          type: boolean
          description: Cuando es `true`, el usuario solo entra por el SSO.
        status:
          type: string
          enum:
            - active
            - suspended
          description: "Transiciones permitidas: `active` ↔ `suspended`."
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por la organización (clave/valor).
    PortalUserEmailPreviewResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            type:
              type: string
              enum:
                - invitation
                - verification
            from:
              type: string
            to:
              type: string
            subject:
              type: string
            message:
              type: string
          required:
            - type
            - from
            - to
            - subject
            - message
      required:
        - data
    PortalUserResendResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            resent:
              type: boolean
            type:
              type: string
              enum:
                - invitation
                - verification
          required:
            - resent
            - type
      required:
        - data
    DashboardUserRoleSummary:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del rol.
        name:
          type: string
          description: Nombre del rol.
        slug:
          type: string
          description: Slug (identificador estable) del rol.
      required:
        - id
        - name
        - slug
    DashboardUserV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público estable del recurso.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización a la que pertenece el usuario.
        person_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la persona (registro de identidad) asociada al usuario, cuando exista.
        external_id:
          type: string
          description: Identificador externo del usuario en Kobana OAuth.
        email:
          type: string
          format: email
          description: Correo del usuario.
        name:
          type:
            - string
            - "null"
          description: Nombre de visualización.
        picture:
          type:
            - string
            - "null"
          description: URL de la foto del usuario.
        status:
          type: string
          enum:
            - active
            - pending_invitation
            - suspended
          description: "Estado actual del usuario: `active`, `pending_invitation` o `suspended`."
        permissions:
          type: array
          items:
            type: string
          description: Permisos ad-hoc asignados directamente al usuario (además de los heredados de los roles).
        last_login_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora del último inicio de sesión.
        login_count:
          type: integer
          description: Cantidad total de inicios de sesión realizados.
        show_getting_started:
          type: boolean
          description: Indica si el panel "Primeros pasos" debe mostrarse al usuario.
        email_signature:
          type:
            - string
            - "null"
          description: Firma de correo configurada por el usuario.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos del sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente.
        created_via:
          type:
            - string
            - "null"
          enum:
            - dashboard
            - import
            - api
            - mcp
            - cli
            - other
          description: Canal por el cual se creó el registro (dashboard, import, api, mcp, cli, other). En las llamadas a la API, viene de la cabecera `X-Request-Source`.
        created_via_other:
          type:
            - string
            - "null"
          description: Nombre de la aplicación que creó el registro cuando `created_via` es `other` (cabecera `X-Request-Source-Other`).
        created_by_email:
          type:
            - string
            - "null"
          description: Correo electrónico del usuario que creó el registro.
        updated_via:
          type:
            - string
            - "null"
          enum:
            - dashboard
            - import
            - api
            - mcp
            - cli
            - other
          description: Canal de la última actualización del registro.
        updated_via_other:
          type:
            - string
            - "null"
          description: Nombre de la aplicación de la última actualización cuando `updated_via` es `other` (cabecera `X-Request-Source-Other`).
        updated_by_email:
          type:
            - string
            - "null"
          description: Correo electrónico del usuario que hizo la última actualización.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        roles:
          type: array
          items:
            $ref: "#/components/schemas/DashboardUserRoleSummary"
          description: Roles asignados al usuario, expandidos como `{ id, name, slug }`.
      required:
        - id
        - public_id
        - organization_id
        - person_id
        - external_id
        - email
        - name
        - picture
        - status
        - permissions
        - last_login_at
        - login_count
        - show_getting_started
        - email_signature
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    DashboardUserListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DashboardUserV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    DashboardUserResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DashboardUserV1"
      required:
        - data
    DashboardUserCreateRequest:
      type: object
      properties:
        email:
          type: string
          format: email
          description: Correo del usuario a invitar.
        name:
          type: string
          description: Nombre del usuario (opcional — el usuario puede completarlo al primer acceso).
        external_id:
          type: string
          description: "Identificador externo del usuario, guardado como atributo del miembro. No define la identidad del usuario: siempre se resuelve por `email`."
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs de roles (`team_roles`) a asignar al usuario. Debe contener al menos un ítem.
        permissions:
          type: array
          items:
            type: string
          description: Permisos ad-hoc adicionales (además de los heredados de los roles). Acepta los mismos slugs de permisos.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
      required:
        - email
        - role_ids
    DashboardUserUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nuevo nombre de visualización.
        picture:
          type: string
          description: URL de la foto del usuario.
        status:
          type: string
          enum:
            - active
            - pending_invitation
            - suspended
          description: "Nuevo estado: `active`, `pending_invitation` o `suspended`."
        permissions:
          type: array
          items:
            type: string
          description: Lista completa de permisos ad-hoc (reemplaza la anterior).
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: Lista completa de UUIDs de roles (reemplaza las asignaciones actuales).
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    TeamRoleV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público estable del recurso.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización a la que pertenece el rol.
        name:
          type: string
          description: Nombre del rol.
        slug:
          type: string
          description: Slug estable del rol.
        description:
          type:
            - string
            - "null"
          description: Descripción del rol.
        permissions:
          type: array
          items:
            type: string
          description: Slugs de permisos concedidos por el rol.
        is_system:
          type: boolean
          description: Indica si el rol es gestionado por el sistema (no editable/removible).
        is_active:
          type: boolean
          description: Indica si el rol está activo y disponible para asignación.
        display_order:
          type: integer
          description: Orden de visualización del rol en las interfaces.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos del rol.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        users_count:
          type: integer
          description: Cantidad de usuarios actualmente vinculados al rol.
      required:
        - id
        - public_id
        - organization_id
        - name
        - slug
        - description
        - permissions
        - is_system
        - is_active
        - display_order
        - metadata
        - external_id
        - custom_metadata
        - created_at
        - updated_at
    TeamRoleListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TeamRoleV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    TeamRoleResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/TeamRoleV1"
      required:
        - data
    TeamRoleCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre del rol (mostrado en la interfaz).
        slug:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          description: "Slug estable usado para referenciar el rol (ej.: `support_manager`)."
          example: portal_manager
        description:
          type: string
          description: Descripción opcional de lo que concede el rol.
        permissions:
          type: array
          items:
            type: string
          description: Lista de slugs de permisos concedidos por el rol.
        is_active:
          type: boolean
          description: Indica si el rol está activo y puede ser asignado.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
      required:
        - name
        - slug
        - permissions
    TeamRoleUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nuevo nombre del rol.
        slug:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          description: Nuevo slug del rol (mismas reglas que en la creación).
        description:
          type: string
          description: Nueva descripción.
        permissions:
          type: array
          items:
            type: string
          description: Lista completa de permisos (reemplaza la anterior).
        is_active:
          type: boolean
          description: Activa o desactiva el rol.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    WorkspaceV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público y estable del workspace.
        name:
          type: string
          description: Nombre del workspace.
        role:
          type:
            - string
            - "null"
          enum:
            - owner
            - member
          description: "Su rol en el workspace: `owner` (lo renombra, elimina y exporta) o `member`. `null` para un token de máquina, que actúa con la autoridad de la organización y no con un acceso concedido."
        max_entity_fields:
          type: integer
          description: Cuántos campos puede tener una nueva entidad del workspace (definido por Kobana).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - name
        - role
        - max_entity_fields
        - created_at
        - updated_at
    WorkspaceListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WorkspaceV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    WorkspaceResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WorkspaceV1"
      required:
        - data
    WorkspaceWriteRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
          description: Nombre del workspace, de 1 a 100 caracteres.
      required:
        - name
    WorkspaceUsageResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            portal_users:
              type: integer
              description: Usuarios del portal del workspace.
            integrations:
              type: integer
              description: Conectores (fuentes de datos) del workspace.
            webhooks:
              type: integer
              description: Webhooks del workspace.
            is_empty:
              type: boolean
              description: "`true` cuando no hay ninguno de los elementos anteriores."
          required:
            - portal_users
            - integrations
            - webhooks
            - is_empty
      required:
        - data
    WorkspaceExportFile:
      type: object
      properties:
        format:
          type: string
          description: "Formato del archivo: `kobana-dashboards.workspace`."
        version:
          type: integer
          description: Versión del formato del archivo.
        exported_at:
          type: string
          format: date-time
      required:
        - format
        - version
    WorkspaceImportRequest:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
          description: El archivo exportado, tal como lo devuelve la exportación.
        name:
          type: string
          maxLength: 100
          description: Nombre del nuevo workspace; por defecto, el del archivo.
      required:
        - data
    WorkspaceImportWarning:
      type: object
      properties:
        code:
          type: string
          enum:
            - connector_credentials_required
            - oauth_secret_required
            - portal_domain_taken
            - signup_slug_taken
            - logos_not_copied
          description: "`connector_credentials_required` (conector en pausa esperando credenciales), `oauth_secret_required` (proveedor OIDC sin secreto), `portal_domain_taken`, `signup_slug_taken` o `logos_not_copied`."
        name:
          type: string
          description: Nombre del conector o proveedor afectado.
        value:
          type: string
          description: Dominio o slug que ya estaba en uso.
      required:
        - code
    WorkspaceImportResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WorkspaceV1"
        counts:
          type: object
          properties:
            connectors:
              type: integer
            entities:
              type: integer
            pages:
              type: integer
            oauth_providers:
              type: integer
          required:
            - connectors
            - entities
            - pages
            - oauth_providers
          description: "Cuánto se creó: conectores, entidades, páginas y proveedores OIDC."
        warnings:
          type: array
          items:
            $ref: "#/components/schemas/WorkspaceImportWarning"
          description: Lo que hay que terminar a mano.
      required:
        - data
        - counts
        - warnings
    WorkspaceGrantV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: ID del workspace.
        name:
          type: string
          description: Nombre del workspace.
        granted:
          type: boolean
          description: "`true` cuando el miembro tiene acceso activo al workspace."
        role:
          type:
            - string
            - "null"
          enum:
            - owner
            - member
          description: Rol del miembro en el workspace (`owner` o `member`); `null` sin acceso.
      required:
        - id
        - name
        - granted
        - role
    WorkspaceGrantListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WorkspaceGrantV1"
      required:
        - data
    WorkspaceGrantReplaceRequest:
      type: object
      properties:
        workspace_ids:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 500
          description: El conjunto final de workspaces a los que el miembro debe acceder. Los quitados se pausan, no se borran.
      required:
        - workspace_ids
    DashboardUserResendResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            resent:
              type: boolean
              example: true
          required:
            - resent
      required:
        - data
    PermissionGroupV1:
      type: object
      properties:
        key:
          type: string
          description: Clave del grupo (el recurso).
        label:
          type: string
          description: Nombre del grupo para mostrar.
        description:
          type: string
        permissions:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
                description: Clave del permiso, como `workspaces.create`.
              label:
                type: string
              description:
                type: string
            required:
              - key
              - label
              - description
      required:
        - key
        - label
        - description
        - permissions
    PermissionCatalogResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PermissionGroupV1"
      required:
        - data
    DataSourceV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        provider:
          type: string
          enum:
            - OPENAPI
            - MCP
            - DATABASE
          description: "Proveedor: `OPENAPI` (API descrita por una spec OpenAPI), `MCP` (servidor MCP) o `DATABASE` (base de datos de solo lectura)."
        kind:
          type: string
          enum:
            - openapi
            - mcp
            - database
          description: "El mismo proveedor en minúsculas: `openapi`, `mcp` o `database`."
        name:
          type: string
        status:
          type: string
          enum:
            - pending
            - active
            - error
            - disabled
          description: "`pending` (guardada y aún no probada, o esperando la autorización OAuth), `active`, `error` (la última prueba falló) o `disabled`."
        is_active:
          type: boolean
        config:
          type: object
          additionalProperties: {}
          description: "Configuración de la conexión sin secretos: Base URL, tipo de autenticación, archivo de la spec, transporte MCP, host de la base… Los valores sensibles de la query string aparecen enmascarados."
        credentials_set:
          type: array
          items:
            type: string
          description: Nombres de los campos secretos configurados (por ejemplo `token`, `password`). Los valores nunca se devuelven.
        oauth_authorized:
          type: boolean
          description: "Servidor MCP con OAuth: `true` cuando ya hay tokens de acceso guardados."
        last_error:
          type:
            - string
            - "null"
          description: Mensaje de la última prueba de conexión que falló; `null` cuando la última funcionó.
        last_tested_at:
          type:
            - string
            - "null"
          format: date-time
        last_synced_at:
          type:
            - string
            - "null"
          format: date-time
        sync_cron:
          type:
            - string
            - "null"
          description: Agenda de sincronización (cron de 5 campos) en la zona horaria `sync_timezone`; `null` para sincronizar solo bajo demanda.
        sync_timezone:
          type:
            - string
            - "null"
        operations_count:
          type: integer
          description: Cantidad de operaciones de la fuente (endpoints, tools o tablas).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - provider
        - kind
        - name
        - status
        - is_active
        - config
        - credentials_set
        - oauth_authorized
        - last_error
        - last_tested_at
        - last_synced_at
        - sync_cron
        - sync_timezone
        - created_at
        - updated_at
    DataSourceOperationV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        key:
          type: string
          description: "Clave estable de la operación: `operationId` (o método + ruta) en OpenAPI, nombre de la tool en MCP, tabla/colección en la base."
        kind:
          type: string
          enum:
            - list
            - retrieve
            - create
            - update
            - delete
            - action
        access:
          type: string
          enum:
            - read
            - write
          description: "`read` (puede alimentar entidades) o `write`."
        name:
          type: string
        description:
          type:
            - string
            - "null"
        method:
          type:
            - string
            - "null"
        path:
          type:
            - string
            - "null"
        external_object:
          type:
            - string
            - "null"
          description: Objeto externo que devuelve la operación (por ejemplo `customer`), cuando se identifica.
        tags:
          type: array
          items:
            type: string
        input_schema:
          description: Parámetros que acepta la operación (JSON Schema).
        output_schema:
          description: Formato de la respuesta (JSON Schema), cuando se conoce.
        fields:
          description: Campos de los registros devueltos, con ruta y tipo.
        records_path:
          type:
            - string
            - "null"
          description: Ruta, en la respuesta, de la lista de registros.
        pagination:
          description: Cómo pagina la operación (página, offset, cursor), cuando se detecta.
        incremental:
          description: Parámetro de lectura incremental (por ejemplo `updated_since`), cuando se detecta.
        enabled:
          type: boolean
          description: Las operaciones desactivadas no alimentan entidades.
        deprecated:
          type: boolean
        position:
          type: integer
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - key
        - kind
        - access
        - name
        - description
        - method
        - path
        - external_object
        - tags
        - records_path
        - enabled
        - deprecated
        - position
        - created_at
        - updated_at
    DataSourceDetailV1:
      allOf:
        - $ref: "#/components/schemas/DataSourceV1"
        - type: object
          properties:
            operations:
              type: array
              items:
                $ref: "#/components/schemas/DataSourceOperationV1"
              description: Operaciones de la fuente, en el orden de `position`.
          required:
            - operations
    DataSourceConnectionTestV1:
      type: object
      properties:
        success:
          type: boolean
        message:
          type: string
          description: Resumen del resultado, en portugués, listo para mostrar.
        http_status:
          type: integer
        duration_ms:
          type: integer
        operation_key:
          type:
            - string
            - "null"
          description: "OpenAPI: operación usada como sonda de la prueba."
        records_found:
          type:
            - integer
            - "null"
        tools_count:
          type: integer
          description: "MCP: tools listadas por el servidor."
        requires_authorization:
          type: boolean
          description: "MCP: el servidor exige autorización OAuth antes de cualquier llamada."
        objects_count:
          type: integer
          description: "Base de datos: tablas, vistas y colecciones encontradas."
      required:
        - success
        - message
    DataSourceRequestLogSummaryV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        service:
          type: string
        method:
          type: string
        endpoint:
          type: string
          description: URL llamada (valores sensibles enmascarados) o la consulta a la base.
        http_status:
          type:
            - integer
            - "null"
        success:
          type: boolean
        error_message:
          type:
            - string
            - "null"
        duration_ms:
          type:
            - integer
            - "null"
        created_at:
          type: string
          format: date-time
      required:
        - id
        - service
        - method
        - endpoint
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
    DataSourceRequestLogV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        service:
          type: string
        method:
          type: string
        endpoint:
          type: string
          description: URL llamada (valores sensibles enmascarados) o la consulta a la base.
        http_status:
          type:
            - integer
            - "null"
        success:
          type: boolean
        error_message:
          type:
            - string
            - "null"
        duration_ms:
          type:
            - integer
            - "null"
        created_at:
          type: string
          format: date-time
        request_headers:
          description: Cabeceras HTTP, con secretos enmascarados.
        request_body:
          type:
            - string
            - "null"
        response_headers:
          description: Cabeceras HTTP, con secretos enmascarados.
        response_body:
          type:
            - string
            - "null"
      required:
        - id
        - service
        - method
        - endpoint
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
        - request_body
        - response_body
    DataSourceCatalogProductV1:
      type: object
      properties:
        key:
          type: string
          description: Clave del producto, usada en `product` al conectar.
        name:
          type: string
        description:
          type: string
        docs_url:
          type: string
        token_help:
          type: string
          description: Dónde obtener el token de API del producto.
        base_urls:
          type: object
          additionalProperties:
            type: string
          description: Base URL por ambiente (`production`, `sandbox`).
        workspace_header:
          type:
            - string
            - "null"
          description: Cabecera con la que el producto elige un workspace dentro de la organización del token, cuando la hay.
      required:
        - key
        - name
        - description
        - docs_url
        - token_help
        - base_urls
        - workspace_header
    DataSourceSpecAnalysisV1:
      type: object
      properties:
        format:
          type: string
          enum:
            - json
            - yaml
        spec_version:
          type: string
        title:
          type: string
        api_version:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        servers:
          type: array
          items:
            type: string
        security_schemes:
          type: array
          items:
            type: object
            additionalProperties: {}
        suggested_auth:
          type: object
          additionalProperties: {}
          description: Autenticación que declara la spec, ya en el formato del campo `auth`.
        suggested_response_format:
          type: string
          enum:
            - json
            - xml
        warnings:
          type: array
          items:
            type: string
        operations_count:
          type: integer
        operations:
          type: array
          items:
            type: object
            properties:
              key:
                type: string
              name:
                type: string
              kind:
                type: string
                enum:
                  - list
                  - retrieve
                  - create
                  - update
                  - delete
                  - action
              access:
                type: string
                enum:
                  - read
                  - write
              method:
                type:
                  - string
                  - "null"
              path:
                type:
                  - string
                  - "null"
              external_object:
                type:
                  - string
                  - "null"
              records_path:
                type:
                  - string
                  - "null"
              pagination: {}
              incremental: {}
              fields_count:
                type: integer
              deprecated:
                type: boolean
            required:
              - key
              - name
              - kind
              - access
              - method
              - path
              - external_object
              - records_path
              - fields_count
              - deprecated
      required:
        - format
        - spec_version
        - title
        - api_version
        - description
        - servers
        - security_schemes
        - suggested_auth
        - suggested_response_format
        - warnings
        - operations_count
        - operations
    DataSourceOpenApiCreateRequest:
      type: object
      properties:
        spec:
          type: string
          description: El documento OpenAPI 3.x o Swagger 2.0 como texto (JSON o YAML), hasta 5 MB — limitado también por los 2 MB de cuerpo de la API.
        spec_file_name:
          type: string
          description: Nombre del archivo de la spec (`openapi.yaml`). Si se omite, se deduce del contenido.
        certificate:
          type: object
          properties:
            filename:
              type: string
              description: "Nombre original del archivo: .pfx, .p12, .pem, .crt o .cer."
            content_base64:
              type: string
              description: El archivo en base64 (hasta 64 KB una vez decodificado).
          required:
            - filename
            - content_base64
          description: Certificado de cliente para mTLS (`auth.kind = "cert"`).
        name:
          type: string
          description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
        base_url:
          type: string
          description: Base URL de la API. Si se omite, usa el primer servidor absoluto de la spec.
        auth:
          type: object
          properties:
            kind:
              type: string
              enum:
                - none
                - header
                - query
                - bearer
                - basic
                - cert
            headers:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  value:
                    type:
                      - string
                      - "null"
                required:
                  - name
            params:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  value:
                    type:
                      - string
                      - "null"
                required:
                  - name
          required:
            - kind
          description: "Cómo autentica la API: `none`, `header`, `query`, `bearer`, `basic` o `cert`. En `header`/`query`, informe los nombres y valores de las claves; un valor en blanco en una actualización mantiene el guardado."
        credentials:
          type: object
          properties:
            token:
              type: string
            username:
              type: string
            password:
              type: string
            certificate_password:
              type: string
          description: "Secretos de la autenticación elegida: `token` (bearer), `username`/`password` (basic), `certificate_password` (cert). Se guardan cifrados y nunca se devuelven."
        response_format:
          type: string
          enum:
            - json
            - xml
      required:
        - spec
    DataSourceMcpCreateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
        url:
          type: string
          description: URL del servidor MCP (endpoint Streamable HTTP o SSE). Un token en la query string se guarda cifrado.
        transport:
          type: string
          enum:
            - http
            - sse
        headers:
          anyOf:
            - type: string
            - type: object
              additionalProperties:
                type: string
          description: "Cabeceras extra enviadas en cada llamada: un objeto, o un `Nombre: valor` por línea. Se guardan cifradas."
        oauth:
          type: object
          properties:
            mode:
              type: string
              enum:
                - none
                - dcr
                - client
            client_id:
              type:
                - string
                - "null"
            client_secret:
              type:
                - string
                - "null"
            scopes:
              type:
                - string
                - "null"
          required:
            - mode
          description: "OAuth del servidor MCP: `none`, `dcr` (registro dinámico de cliente) o `client` (su propio client id/secret)."
      required:
        - url
    DataSourceDatabaseCreateRequest:
      type: object
      properties:
        engine:
          type: string
          enum:
            - postgres
            - mysql
            - mariadb
            - mssql
            - mongodb
        name:
          type: string
          description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
        host:
          type:
            - string
            - "null"
        port:
          anyOf:
            - type: integer
            - type: string
            - type: "null"
        database:
          type:
            - string
            - "null"
        username:
          type:
            - string
            - "null"
        password:
          type:
            - string
            - "null"
        connection_string:
          type:
            - string
            - "null"
          description: "Solo MongoDB: la cadena de conexión completa (en lugar de host, puerto, usuario y contraseña). Autenticación solo por usuario y contraseña (SCRAM); opciones aceptadas: authSource, authMechanism (SCRAM-SHA-1/SCRAM-SHA-256), replicaSet, tls/ssl, retryWrites, retryReads, w, journal, wtimeoutMS, readPreference, readConcernLevel, appName, directConnection, loadBalanced, compressors, zlibCompressionLevel y los tiempos/límites de pool (maxPoolSize, minPoolSize, maxIdleTimeMS, connectTimeoutMS, socketTimeoutMS, serverSelectionTimeoutMS, heartbeatFrequencyMS, localThresholdMS, maxStalenessSeconds). Cualquier otra opción se rechaza con 422."
        ssl:
          type: boolean
        ssl_verify:
          type: boolean
      required:
        - engine
    DataSourceCatalogConnectRequest:
      type: object
      properties:
        product:
          type: string
          description: Clave del producto del catálogo Kobana (vea `GET /data_sources/catalog`).
        environment:
          type: string
          enum:
            - production
            - sandbox
        token:
          type: string
          description: Token de API del producto. Se guarda cifrado.
        workspace_id:
          type:
            - string
            - "null"
          description: Workspace dentro del producto, cuando la organización del token tiene más de uno.
        name:
          type: string
          description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
      required:
        - product
    DataSourceSpecRequest:
      type: object
      properties:
        spec:
          type: string
          description: El documento OpenAPI 3.x o Swagger 2.0 como texto (JSON o YAML), hasta 5 MB — limitado también por los 2 MB de cuerpo de la API.
        spec_file_name:
          type: string
          description: Nombre del archivo de la spec (`openapi.yaml`). Si se omite, se deduce del contenido.
      required:
        - spec
    DataSourceDraftTestRequest:
      anyOf:
        - type: object
          properties:
            kind:
              type: string
              enum:
                - openapi
            spec:
              type: string
              description: El documento OpenAPI 3.x o Swagger 2.0 como texto (JSON o YAML), hasta 5 MB — limitado también por los 2 MB de cuerpo de la API.
            spec_file_name:
              type: string
              description: Nombre del archivo de la spec (`openapi.yaml`). Si se omite, se deduce del contenido.
            certificate:
              type: object
              properties:
                filename:
                  type: string
                  description: "Nombre original del archivo: .pfx, .p12, .pem, .crt o .cer."
                content_base64:
                  type: string
                  description: El archivo en base64 (hasta 64 KB una vez decodificado).
              required:
                - filename
                - content_base64
              description: Certificado de cliente para mTLS (`auth.kind = "cert"`).
            name:
              type: string
              description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
            base_url:
              type: string
              description: Base URL de la API. Si se omite, usa el primer servidor absoluto de la spec.
            auth:
              type: object
              properties:
                kind:
                  type: string
                  enum:
                    - none
                    - header
                    - query
                    - bearer
                    - basic
                    - cert
                headers:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      value:
                        type:
                          - string
                          - "null"
                    required:
                      - name
                params:
                  type: array
                  items:
                    type: object
                    properties:
                      name:
                        type: string
                      value:
                        type:
                          - string
                          - "null"
                    required:
                      - name
              required:
                - kind
              description: "Cómo autentica la API: `none`, `header`, `query`, `bearer`, `basic` o `cert`. En `header`/`query`, informe los nombres y valores de las claves; un valor en blanco en una actualización mantiene el guardado."
            credentials:
              type: object
              properties:
                token:
                  type: string
                username:
                  type: string
                password:
                  type: string
                certificate_password:
                  type: string
              description: "Secretos de la autenticación elegida: `token` (bearer), `username`/`password` (basic), `certificate_password` (cert). Se guardan cifrados y nunca se devuelven."
            response_format:
              type: string
              enum:
                - json
                - xml
          required:
            - kind
            - spec
        - type: object
          properties:
            kind:
              type: string
              enum:
                - mcp
            name:
              type: string
              description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
            url:
              type: string
              description: URL del servidor MCP (endpoint Streamable HTTP o SSE). Un token en la query string se guarda cifrado.
            transport:
              type: string
              enum:
                - http
                - sse
            headers:
              anyOf:
                - type: string
                - type: object
                  additionalProperties:
                    type: string
              description: "Cabeceras extra enviadas en cada llamada: un objeto, o un `Nombre: valor` por línea. Se guardan cifradas."
            oauth:
              type: object
              properties:
                mode:
                  type: string
                  enum:
                    - none
                    - dcr
                    - client
                client_id:
                  type:
                    - string
                    - "null"
                client_secret:
                  type:
                    - string
                    - "null"
                scopes:
                  type:
                    - string
                    - "null"
              required:
                - mode
              description: "OAuth del servidor MCP: `none`, `dcr` (registro dinámico de cliente) o `client` (su propio client id/secret)."
          required:
            - kind
            - url
        - type: object
          properties:
            kind:
              type: string
              enum:
                - database
            engine:
              type: string
              enum:
                - postgres
                - mysql
                - mariadb
                - mssql
                - mongodb
            name:
              type: string
              description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
            host:
              type:
                - string
                - "null"
            port:
              anyOf:
                - type: integer
                - type: string
                - type: "null"
            database:
              type:
                - string
                - "null"
            username:
              type:
                - string
                - "null"
            password:
              type:
                - string
                - "null"
            connection_string:
              type:
                - string
                - "null"
              description: "Solo MongoDB: la cadena de conexión completa (en lugar de host, puerto, usuario y contraseña). Autenticación solo por usuario y contraseña (SCRAM); opciones aceptadas: authSource, authMechanism (SCRAM-SHA-1/SCRAM-SHA-256), replicaSet, tls/ssl, retryWrites, retryReads, w, journal, wtimeoutMS, readPreference, readConcernLevel, appName, directConnection, loadBalanced, compressors, zlibCompressionLevel y los tiempos/límites de pool (maxPoolSize, minPoolSize, maxIdleTimeMS, connectTimeoutMS, socketTimeoutMS, serverSelectionTimeoutMS, heartbeatFrequencyMS, localThresholdMS, maxStalenessSeconds). Cualquier otra opción se rechaza con 422."
            ssl:
              type: boolean
            ssl_verify:
              type: boolean
          required:
            - kind
            - engine
        - type: object
          properties:
            kind:
              type: string
              enum:
                - catalog
            product:
              type: string
              description: Clave del producto del catálogo Kobana (vea `GET /data_sources/catalog`).
            environment:
              type: string
              enum:
                - production
                - sandbox
            token:
              type: string
              description: Token de API del producto. Se guarda cifrado.
            workspace_id:
              type:
                - string
                - "null"
              description: Workspace dentro del producto, cuando la organización del token tiene más de uno.
            name:
              type: string
              description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
          required:
            - kind
            - product
      description: Informe `kind` y el cuerpo de la ruta de creación correspondiente. No se guarda nada.
    DataSourceUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre visible, único por workspace y tipo. Si se omite, se deriva de la spec, del host o de la base.
        is_active:
          type: boolean
        base_url:
          type: string
          description: Base URL de la API. Si se omite, usa el primer servidor absoluto de la spec.
        auth:
          type: object
          properties:
            kind:
              type: string
              enum:
                - none
                - header
                - query
                - bearer
                - basic
                - cert
            headers:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  value:
                    type:
                      - string
                      - "null"
                required:
                  - name
            params:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  value:
                    type:
                      - string
                      - "null"
                required:
                  - name
          required:
            - kind
          description: "Cómo autentica la API: `none`, `header`, `query`, `bearer`, `basic` o `cert`. En `header`/`query`, informe los nombres y valores de las claves; un valor en blanco en una actualización mantiene el guardado."
        credentials:
          type: object
          properties:
            token:
              type: string
            username:
              type: string
            password:
              type: string
            certificate_password:
              type: string
          description: "Secretos de la autenticación elegida: `token` (bearer), `username`/`password` (basic), `certificate_password` (cert). Se guardan cifrados y nunca se devuelven."
        certificate:
          type: object
          properties:
            filename:
              type: string
              description: "Nombre original del archivo: .pfx, .p12, .pem, .crt o .cer."
            content_base64:
              type: string
              description: El archivo en base64 (hasta 64 KB una vez decodificado).
          required:
            - filename
            - content_base64
          description: Certificado de cliente para mTLS (`auth.kind = "cert"`).
        probe_operation_key:
          type:
            - string
            - "null"
          description: "OpenAPI: operación usada como sonda en la prueba de conexión; `null` elige una automáticamente."
        default_params:
          type: object
          additionalProperties:
            type: string
          description: "OpenAPI: valores por defecto de parámetros enviados en cada llamada."
        response_format:
          type: string
          enum:
            - json
            - xml
        url:
          type: string
          description: URL del servidor MCP (endpoint Streamable HTTP o SSE). Un token en la query string se guarda cifrado.
        transport:
          type: string
          enum:
            - http
            - sse
        headers:
          anyOf:
            - type: string
            - type: object
              additionalProperties:
                type: string
          description: "Cabeceras extra enviadas en cada llamada: un objeto, o un `Nombre: valor` por línea. Se guardan cifradas."
        oauth:
          type: object
          properties:
            mode:
              type: string
              enum:
                - none
                - dcr
                - client
            client_id:
              type:
                - string
                - "null"
            client_secret:
              type:
                - string
                - "null"
            scopes:
              type:
                - string
                - "null"
          required:
            - mode
          description: "OAuth del servidor MCP: `none`, `dcr` (registro dinámico de cliente) o `client` (su propio client id/secret)."
        engine:
          type: string
          enum:
            - postgres
            - mysql
            - mariadb
            - mssql
            - mongodb
        host:
          type:
            - string
            - "null"
        port:
          anyOf:
            - type: integer
            - type: string
            - type: "null"
        database:
          type:
            - string
            - "null"
        username:
          type:
            - string
            - "null"
        password:
          type:
            - string
            - "null"
        connection_string:
          type:
            - string
            - "null"
          description: "Solo MongoDB: la cadena de conexión completa (en lugar de host, puerto, usuario y contraseña). Autenticación solo por usuario y contraseña (SCRAM); opciones aceptadas: authSource, authMechanism (SCRAM-SHA-1/SCRAM-SHA-256), replicaSet, tls/ssl, retryWrites, retryReads, w, journal, wtimeoutMS, readPreference, readConcernLevel, appName, directConnection, loadBalanced, compressors, zlibCompressionLevel y los tiempos/límites de pool (maxPoolSize, minPoolSize, maxIdleTimeMS, connectTimeoutMS, socketTimeoutMS, serverSelectionTimeoutMS, heartbeatFrequencyMS, localThresholdMS, maxStalenessSeconds). Cualquier otra opción se rechaza con 422."
        ssl:
          type: boolean
        ssl_verify:
          type: boolean
      description: Campos aceptados según el tipo de la fuente (OpenAPI, MCP o base); los de otro tipo se ignoran. Los campos secretos en blanco mantienen los guardados.
    DataSourceScheduleRequest:
      type: object
      properties:
        cron:
          type:
            - string
            - "null"
          description: Cron de 5 campos (como máximo cada 5 minutos), o `null` para sincronizar solo bajo demanda.
        timezone:
          type:
            - string
            - "null"
          description: "Zona horaria IANA de la agenda. Por defecto: la actual de la fuente, o America/Sao_Paulo."
      required:
        - cron
    DataSourceSyncRequest:
      type: object
      properties:
        full:
          type: boolean
          description: "`true` vuelve a leer todo en lugar de solo lo que cambió desde la última sincronización."
    DataSourceOperationUpdateRequest:
      type: object
      properties:
        enabled:
          type: boolean
          description: Las operaciones desactivadas no alimentan entidades.
      required:
        - enabled
    DataSourceListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DataSourceV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    DataSourceRequestLogListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DataSourceRequestLogSummaryV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    DataSourceResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataSourceV1"
      required:
        - data
    DataSourceDetailResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataSourceDetailV1"
      required:
        - data
    DataSourceOperationResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataSourceOperationV1"
      required:
        - data
    DataSourceRequestLogResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataSourceRequestLogV1"
      required:
        - data
    DataSourceCatalogResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/DataSourceCatalogProductV1"
      required:
        - data
    DataSourceSpecAnalysisResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataSourceSpecAnalysisV1"
      required:
        - data
    DataSourceCreatedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            data_source:
              $ref: "#/components/schemas/DataSourceV1"
            test:
              allOf:
                - $ref: "#/components/schemas/DataSourceConnectionTestV1"
                - type:
                    - object
                    - "null"
          required:
            - data_source
            - test
      required:
        - data
    DataSourceMcpCreatedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            data_source:
              $ref: "#/components/schemas/DataSourceV1"
            test:
              allOf:
                - $ref: "#/components/schemas/DataSourceConnectionTestV1"
                - type:
                    - object
                    - "null"
            authorization_url:
              type:
                - string
                - "null"
              description: Página de autorización OAuth del servidor MCP. Una persona con sesión en el dashboard debe abrirla en el navegador para terminar la conexión; `null` cuando no hay nada que autorizar.
          required:
            - data_source
            - test
            - authorization_url
      required:
        - data
    DataSourceDraftTestResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            test:
              $ref: "#/components/schemas/DataSourceConnectionTestV1"
            operations_count:
              type: integer
              description: "OpenAPI: operaciones que la spec importaría."
          required:
            - test
      required:
        - data
    DataSourceTestResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            test:
              $ref: "#/components/schemas/DataSourceConnectionTestV1"
            data_source:
              $ref: "#/components/schemas/DataSourceV1"
          required:
            - test
            - data_source
      required:
        - data
    DataSourceSyncResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            sync_id:
              type: string
              format: uuid
              description: ID de la ejecución de sincronización.
          required:
            - sync_id
      required:
        - data
    DataSourceScheduleResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            data_source:
              $ref: "#/components/schemas/DataSourceV1"
            next_runs:
              type: array
              items:
                type: string
                format: date-time
              description: Próximas cinco ejecuciones (UTC); vacío cuando es solo bajo demanda.
          required:
            - data_source
            - next_runs
      required:
        - data
    DataSourceSpecResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            data_source:
              $ref: "#/components/schemas/DataSourceV1"
            warnings:
              type: array
              items:
                type: string
          required:
            - data_source
            - warnings
      required:
        - data
    DataSourceAuthorizeResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            authorization_url:
              type:
                - string
                - "null"
              description: Página de autorización OAuth del servidor MCP. Una persona con sesión en el dashboard debe abrirla en el navegador para terminar la conexión; `null` cuando no hay nada que autorizar.
            test:
              allOf:
                - $ref: "#/components/schemas/DataSourceConnectionTestV1"
                - type:
                    - object
                    - "null"
          required:
            - authorization_url
            - test
      required:
        - data
    EntityPaginationV1:
      type: object
      properties:
        style:
          type: string
          enum:
            - none
            - page
            - offset
            - cursor
          description: Estilo de paginación; los demás campos dependen de él.
        page_param:
          type: string
        offset_param:
          type: string
        cursor_param:
          type: string
        size_param:
          type: string
        limit_param:
          type: string
        next_cursor_path:
          type: string
        page_size:
          type: integer
          description: Registros por página pedidos al origen; ausente = el valor por defecto de la sincronización.
      required:
        - style
      description: "Cómo la sincronización pagina el origen: `none`, `page` (`page_param`, `size_param`), `offset` (`offset_param`, `limit_param`) o `cursor` (`cursor_param`, `size_param`, `next_cursor_path`)."
    EntitySyncFilterV1:
      type: object
      properties:
        target:
          type: string
          description: Parámetro de la operación (o columna de la tabla) que recibe el filtro.
        op:
          type: string
          enum:
            - eq
            - neq
            - gt
            - gte
            - lt
            - lte
            - contains
            - starts_with
            - in
            - is_null
            - not_null
        value:
          description: 'Valor del filtro: texto, número, booleano, lista, `null` o una fecha relativa `{ "relative_days": -30 }`.'
      required:
        - target
        - op
    EntityJoinSpecV1:
      type: object
      properties:
        base_entity_id:
          type: string
          format: uuid
          description: "Entidad base: todos sus registros entran en la relación."
        related_entity_id:
          type: string
          format: uuid
          description: Entidad relacionada, emparejada con la base por los campos indicados.
        base_field:
          type: string
          description: Clave del campo de la entidad base usado para emparejar.
        related_field:
          type: string
          description: Clave del campo de la entidad relacionada usado para emparejar.
        type:
          type: string
          enum:
            - inner
            - left
          description: "`left` (por defecto) mantiene los registros de la base sin pareja; `inner` solo los que coinciden."
        match:
          type: string
          enum:
            - exact
            - digits
          description: "`exact` (por defecto) compara el texto; `digits` compara solo los dígitos (un CPF con y sin puntuación coinciden)."
      required:
        - base_entity_id
        - related_entity_id
        - base_field
        - related_field
    EntityFieldV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        key:
          type: string
        name:
          type: string
        data_type:
          type: string
          enum:
            - string
            - int
            - decimal
            - money
            - bool
            - date
            - datetime
            - email
            - enum
            - document
            - phone
            - url
            - file
            - array
            - json
        semantic_role:
          type:
            - string
            - "null"
          enum:
            - identifier
            - reference
            - label
            - status
            - due_date
            - amount
            - created_at
            - updated_at
            - email
            - document
            - phone
            - url
          description: "Rol del campo: identificador, referencia, título, monto, estado, fecha…"
        source_path:
          type: string
          description: Ruta del valor en el registro del origen; vacío en un campo calculado.
        expression:
          type:
            - string
            - "null"
          description: "Campo calculado: plantilla sobre los otros campos, como `P-{{ $resource.numero }}`; `null` en un campo leído del origen."
        format:
          type:
            - string
            - "null"
        enum_options:
          type:
            - array
            - "null"
          items: {}
        visible:
          type: boolean
        filterable:
          type: boolean
        sortable:
          type: boolean
        position:
          type: integer
      required:
        - id
        - key
        - name
        - data_type
        - semantic_role
        - source_path
        - expression
        - format
        - enum_options
        - visible
        - filterable
        - sortable
        - position
    EntitySourceV1:
      type: object
      properties:
        integration_id:
          type: string
          format: uuid
          description: Fuente de datos (conector) de donde lee la entidad.
        integration_name:
          type: string
        kind:
          type: string
          enum:
            - openapi
            - mcp
            - database
          description: "Tipo de fuente de datos: `openapi`, `mcp` o `database`."
        source_kind:
          type: string
          enum:
            - operation
            - sql
            - join
          description: "`operation` (endpoint, tool o tabla), `sql` (consulta en una base SQL) o `join` (relación entre dos entidades)."
        join:
          allOf:
            - $ref: "#/components/schemas/EntityJoinSpecV1"
            - type:
                - object
                - "null"
              description: "En una entidad `join`: las dos entidades, los campos que coinciden y cómo; `null` en las demás."
        operation_id:
          type:
            - string
            - "null"
          format: uuid
        operation_key:
          type:
            - string
            - "null"
        operation_name:
          type:
            - string
            - "null"
        method:
          type:
            - string
            - "null"
        path:
          type:
            - string
            - "null"
        sql:
          type:
            - string
            - "null"
        params:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Parámetros con los que se llama a la operación.
        records_path:
          type:
            - string
            - "null"
        pagination:
          allOf:
            - $ref: "#/components/schemas/EntityPaginationV1"
            - type:
                - object
                - "null"
              description: Paginación de la sincronización; `null` = la detectada en la operación (`operation_pagination`).
        operation_pagination:
          type:
            - object
            - "null"
          additionalProperties: {}
        sync_filters:
          type: array
          items:
            $ref: "#/components/schemas/EntitySyncFilterV1"
      required:
        - integration_id
        - integration_name
        - kind
        - source_kind
        - join
        - operation_id
        - operation_key
        - operation_name
        - method
        - path
        - sql
        - params
        - records_path
        - pagination
        - operation_pagination
        - sync_filters
    EntityV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        key:
          type: string
          description: Nombre de máquina que usan los bloques del portal; único en el workspace (hasta 63 caracteres).
        name:
          type: string
        name_plural:
          type: string
        description:
          type:
            - string
            - "null"
        source:
          $ref: "#/components/schemas/EntitySourceV1"
        sync_mode:
          type: string
          enum:
            - scheduled
            - manual
            - on_access
          description: "Cuándo se ejecuta la sincronización: `scheduled` (programada), `manual` u `on_access` (los registros de cada titular se leen cuando uno de sus usuarios abre el portal)."
        freshness_seconds:
          type: integer
          description: "`on_access`: durante cuántos segundos los registros sincronizados de un titular cuentan como actuales."
        identifier_field_key:
          type:
            - string
            - "null"
        label_field_key:
          type:
            - string
            - "null"
        owner_field_key:
          type:
            - string
            - "null"
          description: Campo con el ID del titular, emparejado con el `tenant_id` del usuario del portal. Sin él la entidad no aparece en el portal.
        owner_match:
          type: string
          enum:
            - external_id
            - document_number
          description: "Cómo se compara el campo del titular con el `tenant_id`: como texto (`external_id`) o como CPF/CNPJ (`document_number`, solo dígitos)."
        fields:
          type: array
          items:
            $ref: "#/components/schemas/EntityFieldV1"
        sampled_at:
          type:
            - string
            - "null"
          format: date-time
        sample:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Algunos registros tal como los devolvió el origen, guardados para volver a inferir campos.
        sync:
          type:
            - object
            - "null"
          properties:
            status:
              type:
                - string
                - "null"
            error:
              type:
                - string
                - "null"
            last_synced_at:
              type:
                - string
                - "null"
              format: date-time
            records_count:
              type: integer
          required:
            - status
            - error
            - last_synced_at
            - records_count
          description: Dónde está la copia de los registros; `null` antes de la primera sincronización.
        created_by_email:
          type:
            - string
            - "null"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - key
        - name
        - name_plural
        - description
        - source
        - sync_mode
        - freshness_seconds
        - identifier_field_key
        - label_field_key
        - owner_field_key
        - owner_match
        - fields
        - sampled_at
        - sample
        - sync
        - created_by_email
        - created_at
        - updated_at
    EntityResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/EntityV1"
      required:
        - data
    EntityListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EntityV1"
      required:
        - data
    EntityRecordV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        external_id:
          type: string
          description: Valor del campo identificador, o un hash del registro cuando la entidad no tiene uno.
        owner_id:
          type:
            - string
            - "null"
          description: Valor del campo del titular, emparejado con el `tenant_id` de los usuarios del portal.
        data:
          type: object
          additionalProperties: {}
          description: Valores del registro por clave de campo — lo que leen bloques, filtros y ordenaciones.
        raw:
          type: object
          additionalProperties: {}
          description: El registro tal como lo devolvió el origen.
        source_updated_at:
          type:
            - string
            - "null"
          format: date-time
        synced_at:
          type: string
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - external_id
        - owner_id
        - data
        - raw
        - source_updated_at
        - synced_at
        - created_at
        - updated_at
    EntityRecordResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            entity:
              $ref: "#/components/schemas/EntityV1"
            record:
              $ref: "#/components/schemas/EntityRecordV1"
          required:
            - entity
            - record
      required:
        - data
    EntityTenantSyncInfoV1:
      type: object
      properties:
        status:
          type: string
          enum:
            - fresh
            - refreshing
            - syncing
            - error
        last_synced_at:
          type:
            - string
            - "null"
          format: date-time
        error:
          type:
            - string
            - "null"
      required:
        - status
        - last_synced_at
        - error
      description: "Con `preview_as` en una entidad `on_access`: dónde está la sincronización de ese titular."
    EntityRecordsQueryResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            records:
              type: array
              items:
                type: object
                additionalProperties: {}
              description: "Valores de cada registro por clave de campo, más `_record: { id, external_id }`."
            total:
              type: integer
            limit:
              type: integer
            offset:
              type: integer
            fields:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                  name:
                    type: string
                  data_type:
                    type: string
                  semantic_role:
                    type:
                      - string
                      - "null"
                required:
                  - key
                  - name
                  - data_type
                  - semantic_role
            synced_at:
              type:
                - string
                - "null"
              format: date-time
            sync:
              allOf:
                - $ref: "#/components/schemas/EntityTenantSyncInfoV1"
                - type:
                    - object
                    - "null"
          required:
            - records
            - total
            - limit
            - offset
            - fields
            - synced_at
      required:
        - data
    EntityRecordsClearedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            cleared:
              type: integer
              description: Cuántos registros se eliminaron.
          required:
            - cleared
      required:
        - data
    EntityAggregateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            value:
              anyOf:
                - type: number
                - type: string
                - type: "null"
              description: Resultado de la agregación, sin `group_by`.
            groups:
              type: array
              items:
                type: object
                properties:
                  key: {}
                  value:
                    anyOf:
                      - type: number
                      - type: string
                      - type: "null"
                required:
                  - value
              description: "Con `group_by`: un resultado por valor del campo (hasta 100 grupos)."
            sync:
              allOf:
                - $ref: "#/components/schemas/EntityTenantSyncInfoV1"
                - type:
                    - object
                    - "null"
      required:
        - data
    EntityUsageResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            pages:
              type: array
              items:
                type: object
                properties:
                  page_id:
                    type: string
                  name:
                    type: string
                  path:
                    type: string
                  blocks:
                    type: array
                    items:
                      type: string
                    description: Tipos de los bloques de la página que leen la entidad, uno por bloque.
                  in_draft:
                    type: boolean
                  in_published:
                    type: boolean
                required:
                  - page_id
                  - name
                  - path
                  - blocks
                  - in_draft
                  - in_published
          required:
            - pages
      required:
        - data
    EntityPreviewResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            source:
              type: object
              properties:
                integration_id:
                  type: string
                  format: uuid
                integration_name:
                  type: string
                kind:
                  type: string
                  enum:
                    - openapi
                    - mcp
                    - database
                source_kind:
                  type: string
                  enum:
                    - operation
                    - sql
                operation_id:
                  type:
                    - string
                    - "null"
                  format: uuid
                operation_key:
                  type:
                    - string
                    - "null"
                operation_name:
                  type: string
                sql:
                  type:
                    - string
                    - "null"
                records_path:
                  type:
                    - string
                    - "null"
              required:
                - integration_id
                - integration_name
                - kind
                - source_kind
                - operation_id
                - operation_key
                - operation_name
                - sql
                - records_path
            max_fields:
              type: integer
              description: Cuántos campos permite el workspace que mantenga la nueva entidad.
            records:
              type: array
              items:
                type: object
                additionalProperties: {}
              description: La muestra de registros devuelta por el origen.
            entity:
              type: object
              properties:
                key:
                  type: string
                name:
                  type: string
                name_plural:
                  type: string
                fields:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
                identifier_field_key:
                  type:
                    - string
                    - "null"
                label_field_key:
                  type:
                    - string
                    - "null"
                owner_field_key:
                  type:
                    - string
                    - "null"
              required:
                - key
                - name
                - name_plural
                - fields
                - identifier_field_key
                - label_field_key
                - owner_field_key
              description: "La entidad propuesta a partir de la muestra: clave, nombres, campos y campos especiales."
            duration_ms:
              type: integer
          required:
            - source
            - max_fields
            - records
            - entity
            - duration_ms
      required:
        - data
    EntityJoinPreviewResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            base:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                key:
                  type: string
                name:
                  type: string
                identifier_field_key:
                  type:
                    - string
                    - "null"
                label_field_key:
                  type:
                    - string
                    - "null"
                owner_field_key:
                  type:
                    - string
                    - "null"
                fields:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
              required:
                - id
                - key
                - name
                - identifier_field_key
                - label_field_key
                - owner_field_key
                - fields
            related:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                key:
                  type: string
                name:
                  type: string
                identifier_field_key:
                  type:
                    - string
                    - "null"
                label_field_key:
                  type:
                    - string
                    - "null"
                owner_field_key:
                  type:
                    - string
                    - "null"
                fields:
                  type: array
                  items:
                    type: object
                    additionalProperties: {}
              required:
                - id
                - key
                - name
                - identifier_field_key
                - label_field_key
                - owner_field_key
                - fields
            stats:
              type: object
              additionalProperties: {}
              description: "Recuentos del emparejamiento: registros de la base, con pareja, sin pareja."
            sample:
              type: array
              items:
                type: object
                additionalProperties: {}
              description: "Las primeras filas combinadas: `{ _id, base: {...}, related: {...} | null }`."
          required:
            - base
            - related
            - stats
            - sample
      required:
        - data
    EntitySyncQueuedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            sync_id:
              type: string
              format: uuid
              description: ID de la sincronización encolada.
          required:
            - sync_id
      required:
        - data
    EntitySyncStateResponse:
      type: object
      properties:
        data:
          type:
            - object
            - "null"
          properties:
            status:
              type:
                - string
                - "null"
              description: Estado de la última sincronización (`queued`, `running`, `completed`, `error`…).
            error:
              type:
                - string
                - "null"
            last_synced_at:
              type:
                - string
                - "null"
              format: date-time
            last_full_sync_at:
              type:
                - string
                - "null"
              format: date-time
            records_count:
              type: integer
            stats:
              type:
                - object
                - "null"
              additionalProperties: {}
          required:
            - status
            - error
            - last_synced_at
            - last_full_sync_at
            - records_count
            - stats
          description: Dónde está la sincronización de la entidad; `null` antes de la primera.
      required:
        - data
    EntityTenantSyncV1:
      type: object
      properties:
        tenant_id:
          type: string
        users:
          type: object
          properties:
            count:
              type: integer
            emails:
              type: array
              items:
                type: string
          required:
            - count
            - emails
          description: "Usuarios del portal con ese Tenant ID: cuántos y los primeros correos."
        status:
          type:
            - string
            - "null"
        error:
          type:
            - string
            - "null"
        last_synced_at:
          type:
            - string
            - "null"
          format: date-time
        last_full_sync_at:
          type:
            - string
            - "null"
          format: date-time
        last_accessed_at:
          type:
            - string
            - "null"
          format: date-time
        records_count:
          type: integer
        stats:
          type: object
          additionalProperties: {}
      required:
        - tenant_id
        - users
        - status
        - error
        - last_synced_at
        - last_full_sync_at
        - last_accessed_at
        - records_count
        - stats
    EntityTenantSyncListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EntityTenantSyncV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    EntityTenantSyncQueuedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            status:
              type: string
              enum:
                - queued
          required:
            - status
      required:
        - data
    EntitySyncLogSummaryV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        service:
          type: string
        method:
          type: string
        endpoint:
          type: string
        http_status:
          type:
            - integer
            - "null"
        success:
          type: boolean
        error_message:
          type:
            - string
            - "null"
        duration_ms:
          type:
            - integer
            - "null"
        created_at:
          type: string
          format: date-time
      required:
        - id
        - service
        - method
        - endpoint
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
    EntitySyncLogListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EntitySyncLogSummaryV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    EntitySyncLogV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        service:
          type: string
        method:
          type: string
        endpoint:
          type: string
        http_status:
          type:
            - integer
            - "null"
        success:
          type: boolean
        error_message:
          type:
            - string
            - "null"
        duration_ms:
          type:
            - integer
            - "null"
        created_at:
          type: string
          format: date-time
        request_headers:
          type:
            - object
            - "null"
          additionalProperties: {}
        request_body:
          type:
            - string
            - "null"
        response_headers:
          type:
            - object
            - "null"
          additionalProperties: {}
        response_body:
          type:
            - string
            - "null"
      required:
        - id
        - service
        - method
        - endpoint
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
        - request_headers
        - request_body
        - response_headers
        - response_body
      description: "Una llamada de la sincronización completa: lo que se envió y lo que volvió (secretos enmascarados al grabar)."
    EntitySyncLogResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/EntitySyncLogV1"
      required:
        - data
    EntityFieldInputV1:
      type: object
      properties:
        key:
          type: string
          maxLength: 63
        name:
          type: string
          maxLength: 200
        data_type:
          type: string
          enum:
            - string
            - int
            - decimal
            - money
            - bool
            - date
            - datetime
            - email
            - enum
            - document
            - phone
            - url
            - file
            - array
            - json
        semantic_role:
          type:
            - string
            - "null"
          enum:
            - identifier
            - reference
            - label
            - status
            - due_date
            - amount
            - created_at
            - updated_at
            - email
            - document
            - phone
            - url
        source_path:
          type: string
          maxLength: 500
          description: Ruta del valor en el registro del origen; vacío en un campo calculado.
        expression:
          type:
            - string
            - "null"
          maxLength: 4000
          description: "Campo calculado: plantilla sobre los otros campos, como `P-{{ $resource.numero }}`; `null` en un campo leído del origen."
        format:
          type:
            - string
            - "null"
          maxLength: 100
        enum_options:
          type:
            - array
            - "null"
          items: {}
          maxItems: 200
        visible:
          type: boolean
          description: Si el campo aparece en los bloques del portal (por defecto `true`).
        filterable:
          type: boolean
        sortable:
          type: boolean
      required:
        - key
        - name
        - data_type
    EntityPreviewRequest:
      type: object
      properties:
        integration_id:
          type: string
          format: uuid
          description: Fuente de datos (conector) de donde leer.
        operation_id:
          type: string
          format: uuid
          description: Operación de lectura (endpoint, tool o tabla) del origen. Envíe este campo o `sql`, no los dos.
        sql:
          type: string
          maxLength: 20000
          description: Consulta SQL en una fuente de base SQL. Envíe este campo o `operation_id`.
        params:
          type: object
          additionalProperties: {}
          description: Parámetros con los que se llama a la operación (por defecto `{}`).
        pagination:
          allOf:
            - $ref: "#/components/schemas/EntityPaginationV1"
            - type:
                - object
                - "null"
              description: Paginación de la sincronización; `null` = la detectada en la operación (`operation_pagination`).
        sync_filters:
          type: array
          items:
            $ref: "#/components/schemas/EntitySyncFilterV1"
          maxItems: 20
          description: Lo que la sincronización envía para filtrar los registros (hasta 20). Ignorado en una consulta SQL.
        limit:
          type: integer
          minimum: 1
          maximum: 50
          description: Tamaño de la muestra (por defecto 10, máximo 50).
      required:
        - integration_id
    EntityCreateRequest:
      type: object
      properties:
        integration_id:
          type: string
          format: uuid
          description: Fuente de datos (conector) de donde leer.
        operation_id:
          type: string
          format: uuid
          description: Operación de lectura (endpoint, tool o tabla) del origen. Envíe este campo o `sql`, no los dos.
        sql:
          type: string
          maxLength: 20000
          description: Consulta SQL en una fuente de base SQL. Envíe este campo o `operation_id`.
        params:
          type: object
          additionalProperties: {}
          description: Parámetros con los que se llama a la operación (por defecto `{}`).
        pagination:
          allOf:
            - $ref: "#/components/schemas/EntityPaginationV1"
            - type:
                - object
                - "null"
              description: Paginación de la sincronización; `null` = la detectada en la operación (`operation_pagination`).
        sync_filters:
          type: array
          items:
            $ref: "#/components/schemas/EntitySyncFilterV1"
          maxItems: 20
          description: Lo que la sincronización envía para filtrar los registros (hasta 20). Ignorado en una consulta SQL.
        key:
          type: string
          maxLength: 63
          description: Nombre de máquina que usan los bloques del portal; único en el workspace (hasta 63 caracteres).
        name:
          type: string
          maxLength: 200
        name_plural:
          type: string
          maxLength: 200
        description:
          type:
            - string
            - "null"
          maxLength: 2000
        identifier_field_key:
          type:
            - string
            - "null"
          maxLength: 63
        label_field_key:
          type:
            - string
            - "null"
          maxLength: 63
        owner_field_key:
          type:
            - string
            - "null"
          maxLength: 63
          description: Campo con el ID del titular, emparejado con el `tenant_id` del usuario del portal. Sin él la entidad no aparece en el portal.
        owner_match:
          type: string
          enum:
            - external_id
            - document_number
          description: "Cómo se compara el campo del titular con el `tenant_id`: como texto (`external_id`) o como CPF/CNPJ (`document_number`, solo dígitos)."
        sync_mode:
          type: string
          enum:
            - scheduled
            - manual
            - on_access
          description: "Cuándo se ejecuta la sincronización; ausente: `scheduled` al crear, se mantiene al actualizar."
        freshness_seconds:
          type: integer
          minimum: 60
          maximum: 604800
          description: "`on_access`: durante cuántos segundos los registros sincronizados de un titular cuentan como actuales."
        fields:
          type: array
          items:
            $ref: "#/components/schemas/EntityFieldInputV1"
          minItems: 1
          maxItems: 200
          description: Los campos que mantiene la entidad, en orden. Al actualizar, la lista completa (emparejada por `key`).
        records_path:
          type:
            - string
            - "null"
          maxLength: 500
          description: Ruta de la lista de registros dentro de la respuesta, cuando no se detecta.
        sample:
          type: array
          items:
            type: object
            additionalProperties: {}
          maxItems: 50
          description: Los registros de la vista previa, guardados para volver a inferir campos después.
      required:
        - integration_id
        - key
        - name
        - name_plural
        - fields
    EntityUpdateRequest:
      type: object
      properties:
        key:
          type: string
          maxLength: 63
          description: Nombre de máquina que usan los bloques del portal; único en el workspace (hasta 63 caracteres).
        name:
          type: string
          maxLength: 200
        name_plural:
          type: string
          maxLength: 200
        description:
          type:
            - string
            - "null"
          maxLength: 2000
        identifier_field_key:
          type:
            - string
            - "null"
          maxLength: 63
        label_field_key:
          type:
            - string
            - "null"
          maxLength: 63
        owner_field_key:
          type:
            - string
            - "null"
          maxLength: 63
          description: Campo con el ID del titular, emparejado con el `tenant_id` del usuario del portal. Sin él la entidad no aparece en el portal.
        owner_match:
          type: string
          enum:
            - external_id
            - document_number
          description: "Cómo se compara el campo del titular con el `tenant_id`: como texto (`external_id`) o como CPF/CNPJ (`document_number`, solo dígitos)."
        sync_mode:
          type: string
          enum:
            - scheduled
            - manual
            - on_access
          description: "Cuándo se ejecuta la sincronización; ausente: `scheduled` al crear, se mantiene al actualizar."
        freshness_seconds:
          type: integer
          minimum: 60
          maximum: 604800
          description: "`on_access`: durante cuántos segundos los registros sincronizados de un titular cuentan como actuales."
        fields:
          type: array
          items:
            $ref: "#/components/schemas/EntityFieldInputV1"
          minItems: 1
          maxItems: 200
          description: Los campos que mantiene la entidad, en orden. Al actualizar, la lista completa (emparejada por `key`).
        pagination:
          allOf:
            - $ref: "#/components/schemas/EntityPaginationV1"
            - type:
                - object
                - "null"
              description: Paginación de la sincronización; `null` = la detectada en la operación (`operation_pagination`).
        sync_filters:
          type: array
          items:
            $ref: "#/components/schemas/EntitySyncFilterV1"
          maxItems: 20
          description: Filtros de la sincronización (hasta 20); ausente mantiene los actuales.
      required:
        - key
        - name
        - name_plural
        - fields
    EntityJoinRequest:
      type: object
      properties:
        key:
          type: string
          maxLength: 63
          description: Nombre de máquina que usan los bloques del portal; único en el workspace (hasta 63 caracteres).
        name:
          type: string
          maxLength: 200
        name_plural:
          type: string
          maxLength: 200
        description:
          type:
            - string
            - "null"
          maxLength: 2000
        join:
          $ref: "#/components/schemas/EntityJoinSpecV1"
        fields:
          type: array
          items:
            type: object
            properties:
              from:
                type: string
                enum:
                  - base
                  - related
              field_key:
                type: string
                maxLength: 63
              key:
                type: string
                maxLength: 63
              name:
                type: string
                maxLength: 200
            required:
              - from
              - field_key
          minItems: 1
          maxItems: 200
          description: "Los campos traídos de cada lado: `{ from: base|related, field_key, key?, name? }`."
        label_field_key:
          type:
            - string
            - "null"
          maxLength: 63
          description: Campo de título; ausente = la copia del título de la entidad base, `null` = ninguno.
        owner_field_key:
          type:
            - string
            - "null"
          maxLength: 63
          description: Campo del titular; ausente = la copia del titular de la entidad base, `null` = ninguno.
      required:
        - key
        - name
        - name_plural
        - join
        - fields
    EntityTenantSyncRequest:
      type: object
      properties:
        tenant_id:
          type: string
          minLength: 1
          maxLength: 500
          description: Tenant ID (ID del titular) a sincronizar. Va en el cuerpo porque puede contener cualquier carácter.
        full:
          type: boolean
          description: Cuando es `true`, vuelve a leer todos los registros del titular.
      required:
        - tenant_id
    PortalBuilderPageSeoV1:
      type: object
      properties:
        description:
          type: string
        keywords:
          type: string
        robots:
          type: string
        canonical:
          type: string
        og_title:
          type: string
        og_description:
          type: string
        og_image:
          type: string
          description: Nombre del archivo de la og:image subida.
        og_image_url:
          type: string
          description: URL pública de la og:image — la que buscan las vistas previas de enlaces (`POST /portal_builder/og_image`).
        og_image_meta:
          type: string
      description: Meta etiquetas y Open Graph de la página; los campos vacíos usan el SEO predeterminado.
    PortalBuilderThemeV1:
      type: object
      properties:
        light:
          type: object
          additionalProperties:
            type: string
          description: Colores de la paleta, por token (`background`, `primary`…).
        dark:
          type: object
          additionalProperties:
            type: string
          description: Colores de la paleta, por token (`background`, `primary`…).
        radius:
          type: string
          description: Radio de los bordes, en `rem` o `px`.
          example: 0.5rem
      required:
        - light
        - dark
        - radius
      description: "Tema visual del portal: paletas clara y oscura y radio de los bordes."
    PortalBuilderSeoDefaultsV1:
      type: object
      properties:
        description:
          type: string
        keywords:
          type: string
        robots:
          type: string
        og_title:
          type: string
        og_description:
          type: string
        og_image:
          type: string
          description: Nombre del archivo de la og:image subida.
        og_image_url:
          type: string
          description: URL pública de la og:image — la que buscan las vistas previas de enlaces (`POST /portal_builder/og_image`).
        og_image_meta:
          type: string
      required:
        - description
        - keywords
        - robots
        - og_title
        - og_description
        - og_image
        - og_image_url
        - og_image_meta
      description: Meta etiquetas y Open Graph que usa toda página que no define los suyos.
    PortalBuilderPageV1:
      type: object
      properties:
        id:
          type: string
          description: Id estable de la página.
        name:
          type: string
          description: Nombre de la página en el constructor y en el menú del portal.
        path:
          type: string
          description: Ruta de la página en la URL del portal.
          example: /
        title:
          type: string
          description: Título de la pestaña del navegador.
        seo:
          $ref: "#/components/schemas/PortalBuilderPageSeoV1"
        show_in_menu:
          type: boolean
          description: Aparece en el menú de la cabecera del portal. Predeterminado `true`.
        content:
          type: object
          additionalProperties: {}
          description: "Árbol de bloques de la página (datos de Puck). Opaco para la API: se guarda y devuelve tal como se envía."
        badge:
          type: string
          enum:
            - ""
            - nova
            - alterada
          description: "Respecto a la versión publicada: `nova` (nueva), `alterada` (modificada) o vacío (igual)."
      required:
        - id
        - name
        - path
        - title
        - seo
        - content
        - badge
    PortalVersionPageV1:
      type: object
      properties:
        id:
          type: string
          description: Id estable de la página.
        name:
          type: string
          description: Nombre de la página en el constructor y en el menú del portal.
        path:
          type: string
          description: Ruta de la página en la URL del portal.
          example: /
        title:
          type: string
          description: Título de la pestaña del navegador.
        seo:
          $ref: "#/components/schemas/PortalBuilderPageSeoV1"
        show_in_menu:
          type: boolean
          description: Aparece en el menú de la cabecera del portal. Predeterminado `true`.
        content:
          type: object
          additionalProperties: {}
          description: "Árbol de bloques de la página (datos de Puck). Opaco para la API: se guarda y devuelve tal como se envía."
      required:
        - id
        - name
        - path
        - title
        - seo
        - content
    PortalVersionV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        number:
          type:
            - integer
            - "null"
          description: Número secuencial de la versión (v1, v2…).
        status:
          type: string
          enum:
            - draft
            - published
            - archived
          description: "`published` (publicada), `archived` (reemplazada) o `draft`."
        note:
          type:
            - string
            - "null"
          description: Nota informada al publicar.
        summary:
          type:
            - string
            - "null"
          description: "Lo que cambió la versión: la nota, o el registro de cambios."
        published_by_email:
          type:
            - string
            - "null"
        published_by_name:
          type:
            - string
            - "null"
        published_at:
          type:
            - string
            - "null"
          format: date-time
      required:
        - id
        - number
        - status
        - note
        - summary
        - published_by_email
        - published_by_name
        - published_at
    PortalBuilderV1:
      type: object
      properties:
        portal:
          type: object
          properties:
            company_name:
              type: string
            title:
              type: string
            subtitle:
              type: string
            public_host:
              type:
                - string
                - "null"
              description: Dirección pública del portal (dominio propio activo, o el predeterminado).
          required:
            - company_name
            - title
            - subtitle
            - public_host
          description: Identidad del portal (Configuración del portal).
        draft:
          type:
            - object
            - "null"
          properties:
            revision:
              type: integer
              description: "Bloqueo optimista del borrador: envíelo en el próximo guardado o publicación."
            dirty:
              type: boolean
              description: "`true` cuando el borrador difiere de la versión publicada."
            pages:
              type: array
              items:
                $ref: "#/components/schemas/PortalBuilderPageV1"
            editor_state:
              type: object
              additionalProperties: {}
              description: Estado que el constructor guarda junto a las páginas (registro de cambios, conexiones). Devuelva lo que leyó.
          required:
            - revision
            - dirty
            - pages
            - editor_state
          description: El borrador; `null` antes de la primera edición.
        live_version:
          type: integer
          description: Número de la versión publicada; `0` cuando no se publicó nada.
        versions:
          type: array
          items:
            $ref: "#/components/schemas/PortalVersionV1"
        theme:
          $ref: "#/components/schemas/PortalBuilderThemeV1"
        seo_defaults:
          $ref: "#/components/schemas/PortalBuilderSeoDefaultsV1"
      required:
        - portal
        - draft
        - live_version
        - versions
        - theme
        - seo_defaults
    PortalBuilderResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalBuilderV1"
      required:
        - data
    PortalBuilderPageInput:
      type: object
      properties:
        id:
          type: string
          description: Id estable de la página (letras, dígitos, `_` y `-`; hasta 100). Único en el borrador.
        name:
          type: string
          description: Nombre de la página en el constructor y en el menú del portal.
        path:
          type: string
          description: Ruta de la página en la URL del portal.
        title:
          type: string
          description: Título de la pestaña del navegador.
        seo:
          $ref: "#/components/schemas/PortalBuilderPageSeoV1"
        show_in_menu:
          type: boolean
          description: Aparece en el menú de la cabecera del portal. Predeterminado `true`.
        content:
          type: object
          additionalProperties: {}
          description: "Árbol de bloques de la página (datos de Puck). Opaco para la API: se guarda y devuelve tal como se envía."
      required:
        - id
        - name
        - path
    PortalBuilderDraftRequest:
      type: object
      properties:
        revision:
          type: integer
          minimum: 0
          description: La última `revision` del borrador leída (`0` cuando aún no hay borrador).
        pages:
          type: array
          items:
            $ref: "#/components/schemas/PortalBuilderPageInput"
          maxItems: 200
          description: Todas las páginas del borrador, en el orden del menú (hasta 200). Las páginas omitidas salen del borrador.
        editor_state:
          type: object
          additionalProperties: {}
          description: Estado del editor; devuelva lo que leyó. Omitido = `{}`.
        theme:
          allOf:
            - $ref: "#/components/schemas/PortalBuilderThemeV1"
            - description: Nuevo tema. Omitido = mantiene el actual.
        seo_defaults:
          allOf:
            - $ref: "#/components/schemas/PortalBuilderSeoDefaultsV1"
            - description: Nuevo SEO predeterminado. Omitido = mantiene el actual.
      required:
        - revision
        - pages
    PortalBuilderPublishRequest:
      type: object
      properties:
        revision:
          type: integer
          minimum: 0
          description: La última `revision` del borrador leída (`0` cuando aún no hay borrador).
        pages:
          type: array
          items:
            $ref: "#/components/schemas/PortalBuilderPageInput"
          maxItems: 200
          description: Todas las páginas del borrador, en el orden del menú (hasta 200). Las páginas omitidas salen del borrador.
        editor_state:
          type: object
          additionalProperties: {}
          description: Estado del editor; devuelva lo que leyó. Omitido = `{}`.
        theme:
          allOf:
            - $ref: "#/components/schemas/PortalBuilderThemeV1"
            - description: Nuevo tema. Omitido = mantiene el actual.
        seo_defaults:
          allOf:
            - $ref: "#/components/schemas/PortalBuilderSeoDefaultsV1"
            - description: Nuevo SEO predeterminado. Omitido = mantiene el actual.
        note:
          type: string
          maxLength: 2000
          description: Lo que cambió, mostrado en el historial de versiones.
      required:
        - revision
        - pages
    PortalBuilderDraftSaveResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            revision:
              type: integer
              description: "Bloqueo optimista del borrador: envíelo en el próximo guardado o publicación."
            dirty:
              type: boolean
              description: "`true` cuando el borrador difiere de la versión publicada."
            badges:
              type: object
              additionalProperties:
                type: string
                enum:
                  - ""
                  - nova
                  - alterada
              description: "Marca de cada página por id: `nova` (nueva), `alterada` (modificada) o vacío."
          required:
            - revision
            - dirty
            - badges
      required:
        - data
    PortalBuilderPublishResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            revision:
              type: integer
              description: "Bloqueo optimista del borrador: envíelo en el próximo guardado o publicación."
            version:
              $ref: "#/components/schemas/PortalVersionV1"
          required:
            - revision
            - version
      required:
        - data
    PortalVersionDetailResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            version:
              $ref: "#/components/schemas/PortalVersionV1"
            pages:
              type: array
              items:
                $ref: "#/components/schemas/PortalVersionPageV1"
          required:
            - version
            - pages
      required:
        - data
    PortalBuilderRollbackResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            version:
              $ref: "#/components/schemas/PortalVersionV1"
            builder:
              $ref: "#/components/schemas/PortalBuilderV1"
          required:
            - version
            - builder
      required:
        - data
    PortalBuilderSecretRequest:
      type: object
      properties:
        value:
          type: string
          minLength: 1
          maxLength: 4000
          description: El valor en texto plano a cifrar. Nunca se devuelve.
        url:
          type: string
          minLength: 1
          maxLength: 2000
          description: "La URL del webhook a la que se destina el valor (obligatoria): el secreto solo se abre para una solicitud al mismo origen (esquema, dominio y puerto). El dominio debe ser fijo — sin `{{variables}}`."
          example: https://hooks.example.com/in
      required:
        - value
        - url
    PortalBuilderSecretResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            value:
              type: string
              description: Valor cifrado (`secret:…`) para guardar en el bloque.
              example: secret:…
          required:
            - value
      required:
        - data
    PortalBuilderOgImageRequest:
      type: object
      properties:
        filename:
          type: string
          minLength: 1
          maxLength: 300
          description: Nombre original del archivo.
          example: cover.png
        content_type:
          type: string
          enum:
            - image/png
            - image/jpeg
            - image/webp
        content_base64:
          type: string
          description: Los bytes de la imagen en base64 (se acepta un prefijo `data:…;base64,`).
      required:
        - filename
        - content_type
        - content_base64
    PortalBuilderOgImageResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            url:
              type: string
              description: URL pública de la imagen.
            content_type:
              type: string
            size:
              type: integer
              description: Tamaño de la imagen, en bytes.
          required:
            - url
            - content_type
            - size
      required:
        - data
    PortalBuilderFormSubmissionRequest:
      type: object
      properties:
        form_id:
          type: string
          minLength: 1
          maxLength: 200
          description: Id del bloque Formulario.
        form_title:
          type: string
          maxLength: 200
        page_path:
          type: string
          maxLength: 500
          description: Ruta de la página donde está el bloque. Predeterminado `/`.
        fields:
          type: array
          items:
            type: object
            properties:
              label:
                type: string
                maxLength: 200
              name:
                type: string
                maxLength: 100
              type:
                type: string
                enum:
                  - text
                  - email
                  - textarea
                  - regex
                  - phone
                  - url
                  - number
                  - currency_brl
                  - currency
                  - cpf
                  - cnpj
                  - cpf_cnpj
              required:
                type: boolean
              pattern:
                type: string
                maxLength: 500
                description: Expresión regular de validación del campo. Una con forma peligrosa (ReDoS) responde 422.
            required:
              - label
          minItems: 1
          maxItems: 30
        action:
          type: object
          properties:
            type:
              type: string
              enum:
                - email
                - webhook
            email_to:
              type: string
              maxLength: 2000
              description: Destinatarios del correo, separados por coma (acción `email`).
            email_subject:
              type: string
              maxLength: 300
            email_template:
              type: string
              maxLength: 20000
            webhook_endpoint_id:
              type: string
              maxLength: 100
              description: Id del webhook del workspace que recibe el envío (acción `webhook`).
          required:
            - type
        values:
          type: object
          additionalProperties:
            type: string
          description: Valores completados, por nombre del campo.
        submitter:
          type: object
          properties:
            name:
              type: string
              maxLength: 200
            email:
              type: string
              maxLength: 254
          description: Cliente que representa la vista previa, para `{{customer_name}}` / `{{customer_email}}`.
      required:
        - form_id
        - fields
        - action
    PortalBuilderFormSubmissionResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            submission_id:
              type: string
            action:
              type: string
              enum:
                - email
                - webhook
            event_id:
              type: string
            recipients:
              type: array
              items:
                type: string
            failed_recipients:
              type: array
              items:
                type: string
            notification_ids:
              type: array
              items:
                type: string
            webhook_delivery_id:
              type:
                - string
                - "null"
            webhook_url:
              type:
                - string
                - "null"
          required:
            - submission_id
            - action
            - event_id
            - recipients
            - failed_recipients
            - notification_ids
            - webhook_delivery_id
            - webhook_url
      required:
        - data
    PortalBuilderActionRunRequest:
      type: object
      properties:
        block_id:
          type: string
          minLength: 1
          maxLength: 200
          description: Id del bloque Botón de acción.
        label:
          type: string
          maxLength: 200
        page_path:
          type: string
          maxLength: 500
          description: Ruta de la página donde está el bloque. Predeterminado `/`.
        request:
          type: object
          properties:
            method:
              type: string
              enum:
                - POST
                - PUT
                - PATCH
            url:
              type: string
              maxLength: 2000
              description: URL completa del webhook; debe empezar con https://.
            headers:
              type: array
              items:
                type: object
                properties:
                  key:
                    type: string
                    maxLength: 200
                  value:
                    type: string
                    maxLength: 8000
                required:
                  - key
                  - value
              maxItems: 50
              description: Cabeceras de la solicitud (hasta 50); un valor puede ser un `secret:` de `POST /portal_builder/secrets`.
            body:
              type: string
              maxLength: 100000
          required:
            - method
            - url
        submitter:
          type: object
          properties:
            name:
              type: string
              maxLength: 200
            email:
              type: string
              maxLength: 254
          description: Cliente que representa la vista previa, para `{{customer_name}}` / `{{customer_email}}`.
      required:
        - block_id
        - request
    PortalBuilderActionRunResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            run_id:
              type: string
            event_id:
              type: string
            success:
              type: boolean
            http_status:
              type:
                - integer
                - "null"
              description: Estado HTTP devuelto por el destino; `null` cuando no hubo respuesta.
            method:
              type: string
            url:
              type: string
            duration_ms:
              type: integer
            error:
              type:
                - string
                - "null"
          required:
            - run_id
            - event_id
            - success
            - http_status
            - method
            - url
            - duration_ms
            - error
      required:
        - data
    PortalColorsV1:
      type: object
      properties:
        primary:
          type: string
        primary_foreground:
          type: string
        secondary:
          type: string
        secondary_foreground:
          type: string
        accent:
          type: string
        accent_foreground:
          type: string
        background:
          type: string
        foreground:
          type: string
        card:
          type: string
        card_foreground:
          type: string
        border:
          type: string
        input:
          type: string
        ring:
          type: string
        destructive:
          type: string
        destructive_foreground:
          type: string
        muted:
          type: string
        muted_foreground:
          type: string
        popover:
          type: string
        popover_foreground:
          type: string
      description: "Colores del tema, en HSL sin `hsl()` (ej.: `210 40% 98%`). Las claves omitidas usan el valor predeterminado."
      example:
        primary: 222 47% 11%
    PortalSettingsV1:
      type: object
      properties:
        id:
          type:
            - string
            - "null"
          format: uuid
          description: ID de la configuración; `null` mientras el portal nunca fue configurado (los valores son los predeterminados).
        workspace_id:
          type: string
          format: uuid
        company_name:
          type: string
          description: "Nombre mostrado en el portal. Predeterminado: el nombre de la organización."
        title:
          type:
            - string
            - "null"
        subtitle:
          type:
            - string
            - "null"
        logo_url:
          type:
            - string
            - "null"
          description: URL pública del logo (fondos claros).
        logo_light_url:
          type:
            - string
            - "null"
          description: URL pública del logo para fondos oscuros.
        favicon_url:
          type:
            - string
            - "null"
        html_lang:
          type: string
          enum:
            - pt-BR
            - en-US
            - es-ES
          description: "El idioma del portal: el atributo `lang` del `<html>` de las páginas y el idioma de las pantallas de inicio de sesión."
        light_colors:
          $ref: "#/components/schemas/PortalColorsV1"
        dark_colors:
          $ref: "#/components/schemas/PortalColorsV1"
        signup_slug:
          type:
            - string
            - "null"
          description: "Dirección del portal en la plataforma: `/portal/{signup_slug}/login`."
        enable_login:
          type: boolean
          description: Interruptor general del inicio de sesión del portal.
        enable_email_login:
          type: boolean
          description: Permite entrar con correo y contraseña o enlace mágico (requiere `enable_login`).
        allow_password_change:
          type: boolean
        sso_enabled:
          type: boolean
          description: Inicio de sesión SSO con un JWT firmado por su sistema.
        sso_public_key:
          type:
            - string
            - "null"
          description: Clave PÚBLICA (PEM) que verifica el JWT de SSO. Nunca envíe la clave privada.
        sso_algorithm:
          type:
            - string
            - "null"
          enum:
            - RS256
            - RS384
            - RS512
            - ES256
            - ES384
            - ES512
            - PS256
            - PS384
            - PS512
        sso_issuer:
          type:
            - string
            - "null"
        portal_slug:
          type:
            - string
            - "null"
          description: Subdominio de la dirección `https://{portal_slug}.{portal_domain}`. Cámbielo con `PATCH /portal_settings/domain`.
        portal_domain:
          type:
            - string
            - "null"
        available_domains:
          type: array
          items:
            type: string
          description: Dominios de la plataforma aceptados en `portal_domain`.
        notification_type_statuses:
          type: object
          properties:
            account_suspended:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            account_activated:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            portal_invitation:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            welcome:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
          description: "Estado de cada notificación del portal: `ACTIVE` (se envía), `INACTIVE` (silenciada) o `DISABLED` (no disponible)."
        notification_bcc_emails:
          type: array
          items:
            type: object
            properties:
              label:
                type: string
                description: Etiqueta de identificación (solo visualización).
              address:
                type: string
                format: email
            required:
              - label
              - address
          description: Destinatarios en copia oculta de todo correo de notificación.
        notification_sender_name:
          type:
            - string
            - "null"
        notification_sender_email:
          type:
            - string
            - "null"
          description: Remitente de los correos de notificación. Solo se usa cuando `notification_sender_email_status` es `active`.
        notification_reply_to_email:
          type:
            - string
            - "null"
        notification_sender_email_status:
          type:
            - string
            - "null"
          enum:
            - pending
            - active
            - failed
          description: "Verificación del remitente en AWS SES: `pending`, `active` o `failed`; `null` cuando no hay remitente propio."
        hsts_include_subdomains:
          type: boolean
        hsts_preload:
          type: boolean
        secure_frame_headers:
          type: boolean
          description: Impide que el portal se muestre dentro de iframes de otros sitios.
        seo_indexing_enabled:
          type: boolean
        seo_robots_txt:
          type:
            - string
            - "null"
        seo_sitemap_enabled:
          type: boolean
        seo_google_site_verification:
          type:
            - string
            - "null"
        seo_canonical_url:
          type:
            - string
            - "null"
        tracking_integrations:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
              anyOf:
                - type: string
                - type: boolean
          description: "Rastreadores por proveedor (`google_tag_manager`, `google_analytics`, …): `{ proveedor: { enabled, ...ids } }`. Los proveedores y campos desconocidos se descartan."
        chat_integrations:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
              anyOf:
                - type: string
                - type: boolean
          description: Widgets de chat por proveedor (`intercom`, `hubspot`, `zendesk`, …), con el mismo formato que `tracking_integrations`.
        custom_code:
          type:
            - string
            - "null"
          description: JavaScript propio ejecutado en todas las páginas del portal.
      required:
        - id
        - workspace_id
        - company_name
        - title
        - subtitle
        - logo_url
        - logo_light_url
        - favicon_url
        - html_lang
        - light_colors
        - dark_colors
        - signup_slug
        - enable_login
        - enable_email_login
        - allow_password_change
        - sso_enabled
        - sso_public_key
        - sso_algorithm
        - sso_issuer
        - portal_slug
        - portal_domain
        - available_domains
        - notification_type_statuses
        - notification_bcc_emails
        - notification_sender_name
        - notification_sender_email
        - notification_reply_to_email
        - notification_sender_email_status
        - hsts_include_subdomains
        - hsts_preload
        - secure_frame_headers
        - seo_indexing_enabled
        - seo_robots_txt
        - seo_sitemap_enabled
        - seo_google_site_verification
        - seo_canonical_url
        - tracking_integrations
        - chat_integrations
        - custom_code
    PortalSettingsResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalSettingsV1"
      required:
        - data
    PortalSettingsUpdateRequest:
      type: object
      properties:
        company_name:
          type: string
          minLength: 1
          maxLength: 100
        title:
          type:
            - string
            - "null"
          maxLength: 100
        subtitle:
          type:
            - string
            - "null"
          maxLength: 200
        html_lang:
          type: string
          enum:
            - pt-BR
            - en-US
            - es-ES
          description: "El idioma del portal: va en el `lang` del `<html>` de las páginas y traduce las pantallas de inicio de sesión."
        light_colors:
          $ref: "#/components/schemas/PortalColorsV1"
        dark_colors:
          $ref: "#/components/schemas/PortalColorsV1"
        signup_slug:
          type:
            - string
            - "null"
          maxLength: 50
          description: Letras minúsculas, números y guiones; único en la plataforma. `null` o `""` lo elimina.
        enable_login:
          type: boolean
        enable_email_login:
          type: boolean
        allow_password_change:
          type: boolean
        sso_enabled:
          type: boolean
        sso_public_key:
          type:
            - string
            - "null"
          maxLength: 10000
        sso_algorithm:
          type:
            - string
            - "null"
          enum:
            - RS256
            - RS384
            - RS512
            - ES256
            - ES384
            - ES512
            - PS256
            - PS384
            - PS512
        sso_issuer:
          type:
            - string
            - "null"
          maxLength: 500
        notification_type_statuses:
          type: object
          properties:
            account_suspended:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            account_activated:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            portal_invitation:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
            welcome:
              type: string
              enum:
                - ACTIVE
                - INACTIVE
                - DISABLED
          description: "Estado de cada notificación del portal: `ACTIVE` (se envía), `INACTIVE` (silenciada) o `DISABLED` (no disponible)."
        notification_bcc_emails:
          type: array
          items:
            type: object
            properties:
              label:
                type: string
                description: Etiqueta de identificación (solo visualización).
              address:
                type: string
                format: email
            required:
              - address
          maxItems: 20
          description: Reemplaza la lista completa (hasta 20).
        notification_sender_name:
          type:
            - string
            - "null"
          maxLength: 100
        notification_sender_email:
          type:
            - string
            - "null"
          maxLength: 254
          description: Una dirección nueva inicia su verificación en AWS SES, que le envía un enlace de confirmación. `""` vuelve al remitente de la plataforma.
        notification_reply_to_email:
          type:
            - string
            - "null"
          maxLength: 254
        hsts_include_subdomains:
          type: boolean
        hsts_preload:
          type: boolean
        secure_frame_headers:
          type: boolean
        seo_indexing_enabled:
          type: boolean
        seo_robots_txt:
          type:
            - string
            - "null"
        seo_sitemap_enabled:
          type: boolean
        seo_google_site_verification:
          type:
            - string
            - "null"
          description: Solo el contenido de la meta etiqueta de verificación de Google.
        seo_canonical_url:
          type:
            - string
            - "null"
          maxLength: 500
        tracking_integrations:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
              anyOf:
                - type: string
                - type: boolean
          description: "Rastreadores por proveedor (`google_tag_manager`, `google_analytics`, …): `{ proveedor: { enabled, ...ids } }`. Los proveedores y campos desconocidos se descartan."
        chat_integrations:
          type: object
          additionalProperties:
            type: object
            additionalProperties:
              anyOf:
                - type: string
                - type: boolean
          description: Widgets de chat por proveedor (`intercom`, `hubspot`, `zendesk`, …), con el mismo formato que `tracking_integrations`.
        custom_code:
          type:
            - string
            - "null"
          maxLength: 100000
      description: 'Actualización parcial: solo cambian los campos enviados. `""` limpia los textos opcionales.'
    PortalLogoUploadRequest:
      type: object
      properties:
        filename:
          type: string
          minLength: 1
          maxLength: 255
          example: logo.png
        content_type:
          type: string
          description: "`image/png`, `image/jpeg` o `image/webp`; el favicon también acepta `image/x-icon`. SVG no se acepta."
          example: image/png
        content_base64:
          type: string
          description: Contenido del archivo en base64 (hasta 500 KB una vez decodificado).
        variant:
          type: string
          enum:
            - logo
            - logo_light
            - favicon
          description: "Qué imagen: `logo` (predeterminado), `logo_light` (logo para fondos oscuros) o `favicon`."
      required:
        - filename
        - content_type
        - content_base64
    PortalLogoUploadResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            variant:
              type: string
              enum:
                - logo
                - logo_light
                - favicon
            url:
              type: string
          required:
            - variant
            - url
      required:
        - data
    PortalLogoDeleteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            variant:
              type: string
              enum:
                - logo
                - logo_light
                - favicon
            deleted:
              type: boolean
          required:
            - variant
            - deleted
      required:
        - data
    PortalDomainUpdateRequest:
      type: object
      properties:
        slug:
          type:
            - string
            - "null"
          minLength: 3
          maxLength: 50
          description: "Subdominio: 3 a 50 letras minúsculas, números y guiones (sin guion en los extremos). `null` para eliminar."
          example: acme
        domain:
          type:
            - string
            - "null"
          description: Uno de los dominios de la plataforma (`available_domains`). `null` para eliminar.
      required:
        - slug
        - domain
    PortalDomainResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            portal_slug:
              type:
                - string
                - "null"
            portal_domain:
              type:
                - string
                - "null"
            full_url:
              type:
                - string
                - "null"
              description: Dirección completa del portal, o `null` cuando no la hay.
          required:
            - portal_slug
            - portal_domain
            - full_url
      required:
        - data
    PortalSlugCheckResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            slug:
              type: string
            domain:
              type: string
            available:
              type: boolean
            reason:
              type:
                - string
                - "null"
              enum:
                - invalid_format
                - reserved
                - invalid_domain
                - taken
              description: "Por qué no está disponible: `invalid_format`, `reserved`, `invalid_domain` o `taken`; `null` cuando lo está."
          required:
            - slug
            - domain
            - available
            - reason
      required:
        - data
    PortalSenderIdentityResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            status:
              type:
                - string
                - "null"
              enum:
                - pending
                - active
                - failed
              description: "Verificación del remitente en AWS SES: `pending`, `active` o `failed`; `null` cuando no hay remitente propio."
            verification_requested:
              type: boolean
              description: "`true` cuando se solicitó una nueva verificación (se envió un correo al remitente)."
          required:
            - status
            - verification_requested
      required:
        - data
    PortalCustomDomainV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        hostname:
          type: string
          example: portal.example.com
        status:
          type: string
          enum:
            - pending_verification
            - dns_verified
            - pending_certificate
            - generating_certificate
            - active
            - certificate_failed
            - failed
          description: "Etapa del aprovisionamiento: `pending_verification`, `dns_verified`, `pending_certificate`, `generating_certificate`, `active`, `certificate_failed` o `failed`."
        verified_at:
          type:
            - string
            - "null"
          format: date-time
        last_verification_at:
          type:
            - string
            - "null"
          format: date-time
        verification_error:
          type:
            - string
            - "null"
        certificate_managed:
          type: boolean
          description: "`true` cuando CloudFront emite y renueva el certificado (basta el CNAME de enrutamiento)."
        certificate_issued_at:
          type:
            - string
            - "null"
          format: date-time
        certificate_expires_at:
          type:
            - string
            - "null"
          format: date-time
        certificate_last_renewal_at:
          type:
            - string
            - "null"
          format: date-time
        certificate_last_renewal_error:
          type:
            - string
            - "null"
        ownership_verified_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se encontró el TXT de propiedad; `null` mientras no — o después de perder la propiedad (`ownership_lost`).
        ownership_lost:
          type: boolean
          description: "`true` cuando el dominio ya se comprobó, pero la verificación diaria dejó de encontrar el TXT `_dashmagico-verify.{hostname}` (3 verificaciones seguidas a lo largo de 7 días o más): el portal deja de responder en él hasta que el TXT se publique de nuevo y el dominio se valide."
        ownership_missing_since:
          type:
            - string
            - "null"
          format: date-time
          description: Desde cuándo la verificación diaria no encuentra el TXT de propiedad de un dominio comprobado (aún no perdido); `null` cuando la última verificación lo encontró.
        dns_records:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - TXT
                  - CNAME
              name:
                type: string
              value:
                type: string
              purpose:
                type: string
                enum:
                  - ownership_verification
                  - routing
                  - certificate_validation
            required:
              - type
              - name
              - value
              - purpose
          description: "Registros DNS que deben publicarse en el dominio. El TXT `_dashmagico-verify.{hostname}` (`ownership_verification`) prueba que el dominio es suyo: su valor es exclusivo de este registro, y nada se aprovisiona ni se enruta antes de él. Mantenga el TXT publicado: la propiedad se verifica de nuevo todos los días, y el dominio la pierde si el registro falta en 3 verificaciones seguidas a lo largo de 7 días o más."
        created_at:
          type: string
          format: date-time
      required:
        - id
        - hostname
        - status
        - verified_at
        - last_verification_at
        - verification_error
        - certificate_managed
        - certificate_issued_at
        - certificate_expires_at
        - certificate_last_renewal_at
        - certificate_last_renewal_error
        - ownership_verified_at
        - ownership_lost
        - ownership_missing_since
        - dns_records
        - created_at
    PortalCustomDomainListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PortalCustomDomainV1"
      required:
        - data
    PortalCustomDomainResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalCustomDomainV1"
      required:
        - data
    PortalCustomDomainCreateRequest:
      type: object
      properties:
        hostname:
          type: string
          minLength: 4
          maxLength: 253
          description: "Nombre completo del dominio, ej.: `portal.ejemplo.com`."
          example: portal.example.com
      required:
        - hostname
    PortalCustomDomainDnsStatusResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            status:
              type: string
              enum:
                - pending_verification
                - dns_verified
                - pending_certificate
                - generating_certificate
                - active
                - certificate_failed
                - failed
            ownership_ok:
              type: boolean
              description: El TXT `_dashmagico-verify.{hostname}` tiene el valor de este dominio (o la propiedad ya se comprobó).
            routing_ok:
              type: boolean
              description: El CNAME de enrutamiento apunta a la plataforma.
            validation_ok:
              type: boolean
              description: El CNAME de validación del certificado es correcto (siempre `true` con certificado gestionado).
            ownership_error:
              type:
                - string
                - "null"
            routing_error:
              type:
                - string
                - "null"
            validation_error:
              type:
                - string
                - "null"
          required:
            - status
            - ownership_ok
            - routing_ok
            - validation_ok
            - ownership_error
            - routing_error
            - validation_error
      required:
        - data
    PortalSettingsDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            id:
              type: string
              format: uuid
            deleted:
              type: boolean
              example: true
          required:
            - id
            - deleted
      required:
        - data
    PortalOAuthProviderV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        enabled:
          type: boolean
        name:
          type: string
        button_label:
          type:
            - string
            - "null"
          description: Texto del botón de inicio de sesión; si está vacío, usa el nombre.
        issuer_url:
          type: string
          description: URL del emisor OpenID Connect (https en producción).
        client_id:
          type: string
        scopes:
          type: string
          description: "Ámbitos separados por espacio. Predeterminado: `openid email profile`."
        email_claim:
          type: string
          description: "Claim del token que trae el correo. Predeterminado: `email`."
        has_secret:
          type: boolean
          description: Si hay un client secret almacenado. El secret nunca se devuelve.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - enabled
        - name
        - button_label
        - issuer_url
        - client_id
        - scopes
        - email_claim
        - has_secret
        - created_at
        - updated_at
    PortalOAuthProviderListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PortalOAuthProviderV1"
      required:
        - data
    PortalOAuthProviderResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalOAuthProviderV1"
      required:
        - data
    PortalOAuthProviderCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        button_label:
          type:
            - string
            - "null"
          maxLength: 100
          description: Texto del botón de inicio de sesión; si está vacío, usa el nombre.
        issuer_url:
          type: string
          maxLength: 2000
          format: uri
          description: URL del emisor OpenID Connect (https en producción).
        client_id:
          type: string
          minLength: 1
          maxLength: 500
        client_secret:
          type: string
          minLength: 1
          maxLength: 2000
          description: "Solo escritura: se guarda cifrado y nunca se devuelve."
        scopes:
          type: string
          maxLength: 500
          description: "Ámbitos separados por espacio. Predeterminado: `openid email profile`."
        email_claim:
          type: string
          maxLength: 100
          description: "Claim del token que trae el correo. Predeterminado: `email`."
        enabled:
          type: boolean
      required:
        - name
        - issuer_url
        - client_id
        - client_secret
    PortalOAuthProviderUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 100
        button_label:
          type:
            - string
            - "null"
          maxLength: 100
        issuer_url:
          type: string
          maxLength: 2000
          format: uri
        client_id:
          type: string
          minLength: 1
          maxLength: 500
        client_secret:
          type: string
          maxLength: 2000
          description: Omitido o vacío mantiene el secret actual; un valor lo reemplaza. Nunca se devuelve.
        scopes:
          type: string
          maxLength: 500
        email_claim:
          type: string
          maxLength: 100
        enabled:
          type: boolean
    PortalOAuthProviderTestRequest:
      type: object
      properties:
        issuer_url:
          type: string
          maxLength: 2000
          format: uri
          description: URL del emisor OpenID Connect (https en producción).
      required:
        - issuer_url
    PortalOAuthProviderTestResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            ok:
              type: boolean
            issuer:
              type:
                - string
                - "null"
            authorization_endpoint:
              type:
                - string
                - "null"
            token_endpoint:
              type:
                - string
                - "null"
            jwks_uri:
              type:
                - string
                - "null"
            error:
              type:
                - string
                - "null"
              description: Motivo de la falla cuando `ok` es `false`.
          required:
            - ok
            - issuer
            - authorization_endpoint
            - token_endpoint
            - jwks_uri
            - error
      required:
        - data
    WebhookV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type:
            - string
            - "null"
          format: uuid
          description: Identificador público del endpoint.
        url:
          type: string
          description: URL que recibe los eventos por POST.
        description:
          type:
            - string
            - "null"
          description: Descripción libre del endpoint.
        auth_type:
          type: string
          enum:
            - none
            - basic
            - bearer
            - header
          description: "Autenticación enviada en cada entrega: `none`, `basic`, `bearer` o `header`."
        active:
          type: boolean
          description: Cuando es `false`, el endpoint está pausado y no recibe entregas.
        workspace_id:
          type: string
          format: uuid
          description: Workspace del endpoint. Recibe los eventos de este workspace y los eventos de la organización.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        events:
          type: array
          items:
            type: string
          description: "Tipos de evento suscritos (ej.: `api_key.db.created`)."
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por la organización.
        delivery_count:
          type: integer
          description: Total de entregas registradas para el endpoint (listado y detalle).
      required:
        - id
        - public_id
        - url
        - description
        - auth_type
        - active
        - workspace_id
        - created_at
        - updated_at
        - events
        - metadata
        - custom_metadata
      description: Endpoint de webhook del workspace. El secreto de firma y las credenciales de autenticación nunca se devuelven aquí.
    WebhookWithSecretV1:
      allOf:
        - $ref: "#/components/schemas/WebhookV1"
        - type: object
          properties:
            secret:
              type: string
              description: Secreto de firma (HMAC-SHA256) en texto plano. Se devuelve SOLO en la creación y en la rotación — guárdelo en ese momento.
              example: whsec_…
          required:
            - secret
      description: Endpoint de webhook del workspace. El secreto de firma y las credenciales de autenticación nunca se devuelven aquí.
    WebhookListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    WebhookResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WebhookV1"
      required:
        - data
    WebhookWithSecretResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WebhookWithSecretV1"
      required:
        - data
    WebhookCreateRequest:
      type: object
      properties:
        url:
          type: string
          description: URL del endpoint (obligatoria en la creación). Debe ser una URL válida.
          example: https://example.com/webhooks
        events:
          type: array
          items:
            type: string
          minItems: 1
          description: Tipos de evento a recibir. Al menos uno.
          example:
            - api_key.db.created
        description:
          type:
            - string
            - "null"
          description: Descripción libre. `null` la limpia.
        auth_type:
          type: string
          enum:
            - none
            - basic
            - bearer
            - header
          description: Autenticación de las entregas (por defecto `none`). Al cambiarla, envíe también el `auth_config` correspondiente.
        auth_config:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: "Credenciales del `auth_type`: basic → `{ username, password }`, bearer → `{ token }`, header → `{ key, value }`. Se guardan cifradas y nunca se devuelven."
          example:
            token: token-123
      required:
        - url
        - events
    WebhookUpdateRequest:
      type: object
      properties:
        url:
          type: string
          description: URL del endpoint (obligatoria en la creación). Debe ser una URL válida.
        events:
          type: array
          items:
            type: string
          minItems: 1
          description: Tipos de evento a recibir. Al menos uno.
        description:
          type:
            - string
            - "null"
          description: Descripción libre. `null` la limpia.
        active:
          type: boolean
          description: "`false` pausa el endpoint; `true` lo reanuda."
        auth_type:
          type: string
          enum:
            - none
            - basic
            - bearer
            - header
          description: Autenticación de las entregas (por defecto `none`). Al cambiarla, envíe también el `auth_config` correspondiente.
        auth_config:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: "Credenciales del `auth_type`: basic → `{ username, password }`, bearer → `{ token }`, header → `{ key, value }`. Se guardan cifradas y nunca se devuelven."
          example:
            token: token-123
    WebhookTestResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            success:
              type: boolean
              description: "`true` cuando el endpoint respondió 2xx."
            status_code:
              type:
                - integer
                - "null"
              description: Estado HTTP de la respuesta; `null` cuando no hubo respuesta.
            delivery_id:
              type: string
              format: uuid
              description: Entrega registrada para el intento.
            error:
              type:
                - string
                - "null"
              description: Motivo del fallo, cuando lo hubo.
          required:
            - success
            - status_code
            - delivery_id
            - error
      required:
        - data
    WebhookDeliveryRetryResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            delivery_id:
              type: string
              format: uuid
            status:
              type: string
              enum:
                - queued
              description: Siempre `queued`.
          required:
            - delivery_id
            - status
      required:
        - data
    WebhookDeliveryV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type:
            - string
            - "null"
          format: uuid
        webhook_endpoint_id:
          type: string
          format: uuid
        event_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
            - pending
            - delivered
            - failed
          description: "`pending` (esperando envío o reintento), `delivered` (2xx) o `failed`."
        http_status:
          type:
            - integer
            - "null"
          description: Estado HTTP devuelto por el endpoint.
        error:
          type:
            - string
            - "null"
          description: Motivo del fallo, cuando lo hubo.
        attempts:
          type: integer
          description: Número de intentos realizados.
        next_retry_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo está programado el próximo intento automático.
        delivered_at:
          type:
            - string
            - "null"
          format: date-time
        created_at:
          type: string
          format: date-time
        request_headers:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Encabezados enviados (autenticación y firma como `[REDACTED]`).
        request_body:
          description: Payload JSON enviado.
        response_headers:
          type:
            - object
            - "null"
          additionalProperties: {}
        response_body:
          type:
            - string
            - "null"
          description: Cuerpo de la respuesta del endpoint (hasta 10.000 caracteres).
        event_type:
          type:
            - string
            - "null"
          description: Tipo del evento entregado (listado global y detalle).
        webhook_endpoint:
          type: object
          properties:
            id:
              type: string
              format: uuid
            url:
              type: string
            description:
              type:
                - string
                - "null"
          required:
            - id
            - url
            - description
          description: Resumen del endpoint de destino (listado global y detalle).
      required:
        - id
        - public_id
        - webhook_endpoint_id
        - event_id
        - status
        - http_status
        - error
        - attempts
        - next_retry_at
        - delivered_at
        - created_at
        - request_headers
        - response_headers
        - response_body
      description: Un intento de entregar un evento a un endpoint de webhook. Los encabezados de autenticación y firma se guardan como `[REDACTED]`.
    WebhookDeliveryListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WebhookDeliveryV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    WebhookDeliveryResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WebhookDeliveryV1"
      required:
        - data
    EventV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        type:
          type: string
          description: Tipo del evento.
          example: api_key.rotated
        resource_type:
          type: string
          description: Tipo del recurso al que se refiere el evento.
        resource_id:
          type: string
          format: uuid
          description: ID del recurso al que se refiere el evento.
        workspace_id:
          type:
            - string
            - "null"
          format: uuid
          description: Workspace del evento; `null` para eventos de la organización (visibles desde todo workspace).
        created_at:
          type: string
          format: date-time
        data:
          description: Payload del evento, tal como se envía a los webhooks.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos del evento.
      required:
        - id
        - type
        - resource_type
        - resource_id
        - workspace_id
        - created_at
        - metadata
      description: Un evento del log — desde donde se disparan los webhooks. Solo lectura.
    EventListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EventV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    EventResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/EventV1"
      required:
        - data
    AuditLogV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        workspace_id:
          type:
            - string
            - "null"
          format: uuid
          description: Workspace del registro; `null` para acciones de la organización.
        user_id:
          type:
            - string
            - "null"
          description: Identificador de quién realizó la acción, cuando se conoce.
        user_email:
          type:
            - string
            - "null"
          description: Correo de quién realizó la acción; `null` para tokens de máquina.
        action:
          type: string
          description: Acción registrada.
          example: webhook.created
        resource_type:
          type: string
          description: Tipo del recurso afectado.
        resource_id:
          type:
            - string
            - "null"
        resource_name:
          type:
            - string
            - "null"
        ip_address:
          type:
            - string
            - "null"
        user_agent:
          type:
            - string
            - "null"
        created_at:
          type: string
          format: date-time
        changes:
          description: Cambios registrados (JSON libre).
        previous_values:
          description: Valores anteriores a la acción (JSON libre).
        new_values:
          description: Valores después de la acción (JSON libre).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: "Contexto adicional (ej.: `via_api`, `token_id`)."
      required:
        - id
        - workspace_id
        - user_id
        - user_email
        - action
        - resource_type
        - resource_id
        - resource_name
        - ip_address
        - user_agent
        - created_at
        - metadata
      description: "Un registro de la auditoría: quién cambió qué, cuándo y desde dónde. Solo lectura."
    AuditLogListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AuditLogV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    AuditLogResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/AuditLogV1"
      required:
        - data
    AuditLogSummaryResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            hours:
              type: number
              description: Ventana usada, en horas.
            since:
              type: string
              format: date-time
              description: Inicio de la ventana.
            total_count:
              type: integer
              description: Total de registros en la ventana.
            action_counts:
              type: array
              items:
                type: object
                properties:
                  action:
                    type: string
                  count:
                    type: integer
                required:
                  - action
                  - count
              description: Las 10 acciones más frecuentes, con el conteo de cada una.
            recent_logs:
              type: array
              items:
                $ref: "#/components/schemas/AuditLogV1"
              description: Los 20 registros más recientes de la ventana.
          required:
            - hours
            - since
            - total_count
            - action_counts
            - recent_logs
      required:
        - data
    EmailTemplateV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público de la plantilla.
        organization_id:
          type:
            - string
            - "null"
          format: uuid
          description: Organización dueña de la plantilla. `null` para una plantilla predeterminada de la plataforma, que solo se puede leer.
        name:
          type: string
          description: Nombre de la plantilla, mostrado a quien edita.
        type:
          type: string
          enum:
            - api_key_expiring
            - account_suspended
            - account_activated
            - portal_invitation
            - portal_signup_verification
            - magic_link_portal
            - magic_link_dashboard
            - email_verification
            - password_reset
            - welcome
            - email_change_verification
            - password_verification
            - account_invitation
            - organization_welcome
            - dashboard_user_welcome
          description: Tipo de notificación que la plantilla renderiza. Cada tipo tiene como máximo una plantilla activa por organización. Una organización solo crea plantillas de `api_key_expiring`, `account_suspended` y `account_activated`; los correos con enlace de acceso o código (invitación al portal, enlace de acceso, verificación, restablecimiento de contraseña) usan siempre el contenido de la plataforma (422 `TEMPLATE_TYPE_NOT_EDITABLE`).
        subject:
          type: string
          description: Asunto del correo. Acepta variables `{{nombre}}`.
        html_body:
          type: string
          description: Cuerpo HTML del correo. Acepta variables `{{nombre}}`, cuyos valores se escapan al renderizar.
        text_body:
          type:
            - string
            - "null"
          description: Cuerpo alternativo en texto plano, cuando lo hay.
        bcc:
          type: array
          items:
            type: string
          description: Direcciones que reciben copia oculta (CCO) de todo correo enviado con esta plantilla.
        variables:
          type: array
          items:
            type: string
          description: Nombres de las variables que usa la plantilla (documentación para quien edita).
        is_active:
          type: boolean
          description: Si es la plantilla activa de su tipo. Las demás son borradores.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por la organización (clave/valor).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - organization_id
        - name
        - type
        - subject
        - html_body
        - text_body
        - bcc
        - variables
        - is_active
        - custom_metadata
        - created_at
        - updated_at
    EmailTemplateListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EmailTemplateV1"
      required:
        - data
    EmailTemplateResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/EmailTemplateV1"
      required:
        - data
    EmailTemplateCreateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre de la plantilla (obligatorio al crear).
        type:
          type: string
          enum:
            - api_key_expiring
            - account_suspended
            - account_activated
            - portal_invitation
            - portal_signup_verification
            - magic_link_portal
            - magic_link_dashboard
            - email_verification
            - password_reset
            - welcome
            - email_change_verification
            - password_verification
            - account_invitation
            - organization_welcome
            - dashboard_user_welcome
          description: Tipo de notificación que la plantilla renderiza (obligatorio).
        subject:
          type: string
          description: Asunto del correo, con variables `{{nombre}}` (obligatorio al crear).
        html_body:
          type: string
          description: Cuerpo HTML, con variables `{{nombre}}` (obligatorio al crear).
        text_body:
          type:
            - string
            - "null"
          description: Cuerpo alternativo en texto plano. `null` lo limpia.
        bcc:
          anyOf:
            - type: array
              items:
                type: string
            - type: string
            - type: "null"
          description: Lista (o una sola dirección) de correos en copia oculta. Direcciones inválidas devuelven 422; si se omite al actualizar, se mantiene la lista actual.
        variables:
          type: array
          items:
            type: string
          description: Nombres de las variables que usa la plantilla.
        is_active:
          type: boolean
          description: Hace de esta la plantilla activa del tipo; la activa anterior pasa a borrador. Por defecto `false` al crear.
      required:
        - name
        - type
        - subject
        - html_body
    EmailTemplateUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre de la plantilla (obligatorio al crear).
        subject:
          type: string
          description: Asunto del correo, con variables `{{nombre}}` (obligatorio al crear).
        html_body:
          type: string
          description: Cuerpo HTML, con variables `{{nombre}}` (obligatorio al crear).
        text_body:
          type:
            - string
            - "null"
          description: Cuerpo alternativo en texto plano. `null` lo limpia.
        bcc:
          anyOf:
            - type: array
              items:
                type: string
            - type: string
            - type: "null"
          description: Lista (o una sola dirección) de correos en copia oculta. Direcciones inválidas devuelven 422; si se omite al actualizar, se mantiene la lista actual.
        variables:
          type: array
          items:
            type: string
          description: Nombres de las variables que usa la plantilla.
        is_active:
          type: boolean
          description: Hace de esta la plantilla activa del tipo; la activa anterior pasa a borrador. Por defecto `false` al crear.
        public_id:
          type: string
          format: uuid
          description: Nuevo identificador público (UUID), cuando la organización permite elegirlo.
    EmailTemplateDuplicateRequest:
      type: object
      properties:
        new_name:
          type: string
          description: 'Nombre de la copia. Por defecto: "<nombre> (Cópia)".'
    EmailTemplateRenderRequest:
      type: object
      properties:
        variables:
          type: object
          additionalProperties: {}
          description: Valores de las variables `{{nombre}}` de la plantilla.
    EmailTemplateRenderResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            subject:
              type: string
              description: Asunto renderizado.
            html_body:
              type: string
              description: Cuerpo HTML renderizado.
            text_body:
              type:
                - string
                - "null"
              description: Cuerpo en texto plano renderizado, cuando la plantilla tiene uno.
            bcc:
              type: array
              items:
                type: string
              description: Copias ocultas de la plantilla (solo en la vista previa con datos de ejemplo).
          required:
            - subject
            - html_body
            - text_body
      required:
        - data
    EmailTemplateDefaultsResponse:
      type: object
      properties:
        data:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - api_key_expiring
                  - account_suspended
                  - account_activated
                  - portal_invitation
                  - portal_signup_verification
                  - magic_link_portal
                  - magic_link_dashboard
                  - email_verification
                  - password_reset
                  - welcome
                  - email_change_verification
                  - password_verification
                  - account_invitation
                  - organization_welcome
                  - dashboard_user_welcome
                description: Tipo de notificación.
              created:
                type: boolean
                description: La plantilla se creó ahora.
              updated:
                type: boolean
                description: La plantilla existente se sobrescribió con la predeterminada.
              id:
                type:
                  - string
                  - "null"
                format: uuid
                description: ID de la plantilla creada o actualizada.
              error:
                type:
                  - string
                  - "null"
                description: Motivo del fallo para este tipo, cuando lo hubo.
            required:
              - type
              - created
              - updated
              - id
              - error
      required:
        - data
    EmailLayoutV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público del diseño.
        organization_id:
          type: string
          format: uuid
          description: Organización dueña del diseño.
        name:
          type: string
          description: Nombre del diseño.
        html_body:
          type: string
          description: Documento HTML que envuelve el cuerpo de los correos, en el marcador `{{content}}`. Los correos con enlace de acceso o código usan siempre el diseño de la plataforma.
        is_default:
          type: boolean
          description: Si es el diseño predeterminado de la organización (como máximo uno).
        is_active:
          type: boolean
          description: Si el diseño está activo.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por la organización (clave/valor).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - organization_id
        - name
        - html_body
        - is_default
        - is_active
        - custom_metadata
        - created_at
        - updated_at
    EmailLayoutListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/EmailLayoutV1"
      required:
        - data
    EmailLayoutResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/EmailLayoutV1"
      required:
        - data
    EmailLayoutCreateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre del diseño (obligatorio al crear).
        html_body:
          type: string
          description: Documento HTML con el marcador `{{content}}` (obligatorio al crear; sin el marcador, 422).
        is_default:
          type: boolean
          description: Hace de este el diseño predeterminado; el anterior deja de serlo.
      required:
        - name
        - html_body
    EmailLayoutUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre del diseño (obligatorio al crear).
        html_body:
          type: string
          description: Documento HTML con el marcador `{{content}}` (obligatorio al crear; sin el marcador, 422).
        is_default:
          type: boolean
          description: Hace de este el diseño predeterminado; el anterior deja de serlo.
        is_active:
          type: boolean
          description: Activa o desactiva el diseño.
    NotificationV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público de la notificación.
        workspace_id:
          type:
            - string
            - "null"
          format: uuid
          description: Workspace de la notificación. `null` para una notificación de toda la organización.
        type:
          type: string
          enum:
            - api_key_expiring
            - account_suspended
            - account_activated
            - portal_invitation
            - portal_signup_verification
            - magic_link_portal
            - magic_link_dashboard
            - email_verification
            - password_reset
            - welcome
            - email_change_verification
            - password_verification
            - account_invitation
            - organization_welcome
            - dashboard_user_welcome
          description: Tipo de notificación.
        channel:
          type: string
          enum:
            - email
            - in_app
            - webhook
          description: Canal de envío.
        status:
          type: string
          enum:
            - pending
            - sent
            - delivered
            - failed
            - read
            - skipped
          description: "`pending` (en cola), `sent`, `delivered`, `read`, `failed` o `skipped` (no enviada porque el tipo estaba inactivo)."
        template_id:
          type:
            - string
            - "null"
          format: uuid
          description: Plantilla de correo usada, cuando la hubo.
        recipient:
          type: string
          description: Dirección de destino.
        recipient_type:
          type:
            - string
            - "null"
          description: "Tipo de destinatario: `portal_user`, `dashboard_user`, `organization` o `external`."
        recipient_id:
          type:
            - string
            - "null"
          format: uuid
          description: ID del destinatario, cuando es un registro.
        subject:
          type:
            - string
            - "null"
          description: Asunto renderizado.
        content:
          type:
            - string
            - "null"
          description: Cuerpo renderizado.
        variables:
          type: object
          additionalProperties: {}
          description: Variables usadas al renderizar (sin las claves internas `__*` del envío).
        sent_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se envió.
        delivered_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se entregó.
        read_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se leyó.
        failure_reason:
          type:
            - string
            - "null"
          description: Motivo del último fallo de envío.
        retry_count:
          type: integer
          description: Reintentos de envío hasta ahora.
        scheduled_for:
          type:
            - string
            - "null"
          format: date-time
          description: Envío programado para, cuando lo hay.
        resource_type:
          type:
            - string
            - "null"
          description: Tipo de registro al que se refiere la notificación.
        resource_id:
          type:
            - string
            - "null"
          format: uuid
          description: ID del registro al que se refiere la notificación.
        template:
          type:
            - object
            - "null"
          properties:
            name:
              type:
                - string
                - "null"
            type:
              type:
                - string
                - "null"
              enum:
                - api_key_expiring
                - account_suspended
                - account_activated
                - portal_invitation
                - portal_signup_verification
                - magic_link_portal
                - magic_link_dashboard
                - email_verification
                - password_reset
                - welcome
                - email_change_verification
                - password_verification
                - account_invitation
                - organization_welcome
                - dashboard_user_welcome
          required:
            - name
            - type
          description: Nombre y tipo de la plantilla usada (solo en el listado).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - workspace_id
        - type
        - channel
        - status
        - template_id
        - recipient
        - recipient_type
        - recipient_id
        - subject
        - content
        - variables
        - sent_at
        - delivered_at
        - read_at
        - failure_reason
        - retry_count
        - scheduled_for
        - resource_type
        - resource_id
        - template
        - created_at
        - updated_at
    NotificationListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/NotificationV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    NotificationResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/NotificationV1"
      required:
        - data
    NotificationSendResponse:
      type: object
      properties:
        data:
          allOf:
            - $ref: "#/components/schemas/NotificationV1"
            - type:
                - object
                - "null"
      required:
        - data
    NotificationCreateRequest:
      type: object
      properties:
        type:
          type: string
          enum:
            - api_key_expiring
            - account_suspended
            - account_activated
            - portal_invitation
            - portal_signup_verification
            - magic_link_portal
            - magic_link_dashboard
            - email_verification
            - password_reset
            - welcome
            - email_change_verification
            - password_verification
            - account_invitation
            - organization_welcome
            - dashboard_user_welcome
          description: "Tipo de notificación (obligatorio): elige la plantilla activa de la organización, o la predeterminada de la plataforma."
        recipient:
          type: string
          description: Dirección de destino (obligatoria) — un correo en el canal `email`.
        channel:
          type: string
          enum:
            - email
            - in_app
            - webhook
          description: Canal de envío. Por defecto `email`.
        portal_user_id:
          type:
            - string
            - "null"
          format: uuid
          description: Usuario del portal al que se destina la notificación; debe ser de la organización (si no, 404).
        resource_type:
          type:
            - string
            - "null"
          description: Tipo del registro relacionado.
        resource_id:
          type:
            - string
            - "null"
          format: uuid
          description: ID (UUID) del registro relacionado.
        scheduled_for:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora ISO 8601 para enviar, en lugar de inmediatamente.
        variables:
          type: object
          additionalProperties:
            anyOf:
              - type: string
              - type: number
              - type: boolean
              - type: "null"
              - type: "null"
          description: "Valores de las variables de la plantilla: hasta 100, nombres con letras, dígitos, `_`, `.` o `-`; valores texto (hasta 10.000 caracteres), número, booleano o `null`."
      required:
        - type
        - recipient
    NotificationStatsResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            total:
              type: integer
              description: Notificaciones creadas en la ventana.
            by_status:
              type: object
              additionalProperties:
                type: integer
              description: Conteo por estado.
            by_channel:
              type: object
              additionalProperties:
                type: integer
              description: Conteo por canal.
            by_type:
              type: object
              additionalProperties:
                type: integer
              description: Conteo por tipo.
            delivery_rate:
              type: number
              description: (enviadas + entregadas) / total, entre 0 y 1.
            read_rate:
              type: number
              description: leídas / total, entre 0 y 1.
          required:
            - total
            - by_status
            - by_channel
            - by_type
            - delivery_rate
            - read_rate
      required:
        - data
    ApiKeyV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type:
            - string
            - "null"
        source:
          type: string
          enum:
            - api
            - dashboard
            - manage
          description: "Dónde se usa la clave: `api`, `dashboard` o `manage`."
        prefix:
          type: string
          description: Inicio visible de la clave (`kb_xxxxxxxx...`), para reconocerla sin el secreto.
        status:
          type: string
          enum:
            - active
            - disabled
            - revoked
          description: "`active`, `disabled` (puede reactivarse) o `revoked` (definitivo)."
        notification_emails:
          type: array
          items:
            type: string
          description: "Quién recibe los avisos de vencimiento. Vacío: el creador."
        created_by_email:
          type:
            - string
            - "null"
        updated_by_email:
          type:
            - string
            - "null"
        enabled_by_email:
          type:
            - string
            - "null"
        disabled_by_email:
          type:
            - string
            - "null"
        revoked_by_email:
          type:
            - string
            - "null"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        last_used_at:
          type:
            - string
            - "null"
          format: date-time
        enabled_at:
          type:
            - string
            - "null"
          format: date-time
        disabled_at:
          type:
            - string
            - "null"
          format: date-time
        revoked_at:
          type:
            - string
            - "null"
          format: date-time
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: "Cuándo vence la clave (`null`: nunca)."
        rotated_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo la clave fue reemplazada por una sucesora.
      required:
        - id
        - name
        - description
        - source
        - prefix
        - status
        - notification_emails
        - created_by_email
        - updated_by_email
        - enabled_by_email
        - disabled_by_email
        - revoked_by_email
        - created_at
        - updated_at
        - last_used_at
        - enabled_at
        - disabled_at
        - revoked_at
        - expires_at
        - rotated_at
    ApiKeyListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ApiKeyV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ApiKeyResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ApiKeyV1"
      required:
        - data
    ApiKeyWithSecretV1:
      allOf:
        - $ref: "#/components/schemas/ApiKeyV1"
        - type: object
          properties:
            key:
              type: string
              description: El secreto en texto claro. Se muestra solo en esta respuesta — guárdelo ahora.
          required:
            - key
    ApiKeyCreatedResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ApiKeyWithSecretV1"
      required:
        - data
    ApiKeyRotatedV1:
      allOf:
        - $ref: "#/components/schemas/ApiKeyV1"
        - type: object
          properties:
            key:
              type: string
              description: El secreto en texto claro. Se muestra solo en esta respuesta — guárdelo ahora.
            previous_key:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                rotated_at:
                  type: string
                  format: date-time
                grace_until:
                  type: string
                  format: date-time
                  description: Fin del plazo de gracia de la clave anterior.
              required:
                - id
                - rotated_at
                - grace_until
              description: La clave reemplazada y hasta cuándo sigue valiendo.
          required:
            - key
            - previous_key
    ApiKeyRotatedResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ApiKeyRotatedV1"
      required:
        - data
    ApiKeyCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre de la clave (obligatorio).
        description:
          type:
            - string
            - "null"
        source:
          type: string
          enum:
            - api
            - dashboard
            - manage
          description: Dónde se usará la clave. Por defecto `dashboard`.
        notification_emails:
          type: array
          items:
            type: string
          description: Correos que reciben los avisos de vencimiento.
        expires_at:
          type: string
          format: date-time
          description: "Vencimiento (fecha-hora ISO 8601 en el futuro). Por defecto: dentro de un año."
      required:
        - name
    ApiKeyUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
        description:
          type:
            - string
            - "null"
        source:
          type: string
          enum:
            - api
            - dashboard
            - manage
        notification_emails:
          type: array
          items:
            type: string
          description: Correos que reciben los avisos de vencimiento.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Nuevo vencimiento (ISO 8601); `null` quita el vencimiento.
        enabled:
          type: boolean
          description: "`false` desactiva la clave; `true` la reactiva."
    ApiKeyRotateRequest:
      type: object
      properties:
        grace_days:
          type: integer
          minimum: 0
          maximum: 30
          description: Días en que la clave anterior sigue valiendo (0 a 30, por defecto 7).
    ExportV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        resource_type:
          type: string
          description: Recurso exportado.
        format:
          type: string
          enum:
            - csv
            - xlsx
            - json
        status:
          type: string
          enum:
            - pending
            - processing
            - completed
            - failed
          description: "`pending`, `processing`, `completed` o `failed`."
        file_name:
          type:
            - string
            - "null"
        file_size_bytes:
          type:
            - integer
            - "null"
        total_rows:
          type:
            - integer
            - "null"
        filters:
          type: object
          additionalProperties: {}
          description: Filtros aplicados a las filas exportadas.
        error_message:
          type:
            - string
            - "null"
        download_available:
          type: boolean
          description: "`true` cuando el archivo puede descargarse en `/download`."
        started_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo el archivo deja de estar disponible.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - resource_type
        - format
        - status
        - file_name
        - file_size_bytes
        - total_rows
        - filters
        - error_message
        - download_available
        - started_at
        - completed_at
        - expires_at
        - created_at
        - updated_at
    ExportListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ExportV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ExportResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ExportV1"
      required:
        - data
    ExportCreateRequest:
      type: object
      properties:
        resource_type:
          type: string
          enum:
            - portal_users
          description: "Qué exportar. Hoy: `portal_users`."
        format:
          type: string
          enum:
            - csv
            - xlsx
            - json
          description: "`csv` (por defecto), `xlsx` o `json`."
        filters:
          type: object
          additionalProperties: {}
          description: Filtros opcionales de las filas exportadas.
      required:
        - resource_type
    ImportV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        resource_type:
          type: string
          description: Recurso importado.
        status:
          type: string
          enum:
            - pending
            - processing
            - completed
            - completed_with_errors
            - failed
          description: "`pending`, `processing`, `completed`, `completed_with_errors` o `failed`."
        file_name:
          type:
            - string
            - "null"
        file_size_bytes:
          type:
            - integer
            - "null"
        total_rows:
          type:
            - integer
            - "null"
        processed_rows:
          type: integer
        success_count:
          type: integer
        error_count:
          type: integer
        errors:
          type: array
          items: {}
          description: Errores por fila registrados durante el procesamiento.
        error_message:
          type:
            - string
            - "null"
        started_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - resource_type
        - status
        - file_name
        - file_size_bytes
        - total_rows
        - processed_rows
        - success_count
        - error_count
        - errors
        - error_message
        - started_at
        - completed_at
        - created_at
        - updated_at
    ImportListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ImportV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ImportResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ImportV1"
      required:
        - data
    ImportCreateRequest:
      type: object
      properties:
        resource_type:
          type: string
          enum:
            - portal_users
          description: "Qué importar. Hoy: `portal_users`."
        file_name:
          type: string
          minLength: 1
          description: Nombre original del archivo, p. ej. `usuarios.csv`.
        content_type:
          type: string
          description: Tipo de archivo. Por defecto `text/csv`.
        content_base64:
          type: string
          minLength: 1
          description: El CSV codificado en base64.
      required:
        - resource_type
        - file_name
        - content_base64
    BackupV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        type:
          type: string
          enum:
            - backup
            - restore
          description: "`backup` (copia generada) o `restore` (restauración)."
        status:
          type: string
          enum:
            - pending
            - processing
            - completed
            - failed
            - canceled
        file_name:
          type:
            - string
            - "null"
        file_size_bytes:
          type:
            - integer
            - "null"
        resource_counts:
          type: object
          additionalProperties:
            type: number
          description: Cantidad de registros por recurso en el archivo.
        progress:
          type: integer
          description: Progreso de 0 a 100.
        current_resource:
          type:
            - string
            - "null"
        error_message:
          type:
            - string
            - "null"
        requested_by:
          type:
            - string
            - "null"
          description: Quién lo pidió (correo, o `api:<id del token>` para un token de máquina).
        download_available:
          type: boolean
          description: "`true` cuando el ZIP de una copia terminada puede descargarse."
        started_at:
          type:
            - string
            - "null"
          format: date-time
        completed_at:
          type:
            - string
            - "null"
          format: date-time
        expires_at:
          type:
            - string
            - "null"
          format: date-time
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - type
        - status
        - file_name
        - file_size_bytes
        - resource_counts
        - progress
        - current_resource
        - error_message
        - requested_by
        - download_available
        - started_at
        - completed_at
        - expires_at
        - created_at
        - updated_at
    BackupListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BackupV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
        backup_allowed:
          type: boolean
          description: Si puede pedirse una nueva copia ahora.
        next_backup_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se libera la próxima copia (`null` si ya lo está).
      required:
        - data
        - meta
        - backup_allowed
        - next_backup_at
    BackupResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/BackupV1"
      required:
        - data
    BackupRestoreRequest:
      type: object
      properties:
        backup_id:
          type: string
          format: uuid
          description: Copia terminada de esta organización a restaurar.
        file_name:
          type: string
          description: Nombre del archivo `.zip`, junto con `content_base64`.
        content_base64:
          type: string
          description: El ZIP de la copia en base64.
    DataPurgeCountsV1:
      type: object
      properties:
        counts:
          type: object
          properties:
            portal_users:
              type: integer
            people:
              type: integer
            usage_history:
              type: integer
          required:
            - portal_users
            - people
            - usage_history
          description: Registros por recurso, sumando todos los workspaces.
      required:
        - counts
    DataPurgeCountsResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataPurgeCountsV1"
      required:
        - data
    DataPurgeRequest:
      type: object
      properties:
        resources:
          type: array
          items:
            type: string
            enum:
              - portal_users
              - people
              - usage_history
          minItems: 1
          description: "Qué eliminar: `portal_users`, `people`, `usage_history`."
        confirm:
          type: string
          description: "Confirmación: el ID de la organización, escrito de nuevo."
      required:
        - resources
        - confirm
    DataPurgeQueuedV1:
      type: object
      properties:
        job_id:
          type: string
          description: ID del job de limpieza.
        status:
          type: string
          enum:
            - queued
        resources:
          type: array
          items:
            type: string
            enum:
              - portal_users
              - people
              - usage_history
      required:
        - job_id
        - status
        - resources
    DataPurgeQueuedResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataPurgeQueuedV1"
      required:
        - data
    DataPurgeJobV1:
      type: object
      properties:
        job_id:
          type: string
        status:
          type: string
          description: "Estado del job en la cola: `waiting`, `active`, `completed`, `failed`…"
        progress:
          type: number
          description: Progreso de 0 a 100.
        result:
          description: Resultado del job al terminar (registros eliminados por recurso).
        failed_reason:
          type:
            - string
            - "null"
      required:
        - job_id
        - status
        - progress
        - failed_reason
    DataPurgeJobResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DataPurgeJobV1"
      required:
        - data
    MaintenanceUppercaseNamesV1:
      type: object
      properties:
        updated:
          type: integer
          description: Número de nombres modificados.
      required:
        - updated
    MaintenanceUppercaseNamesResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/MaintenanceUppercaseNamesV1"
      required:
        - data
    OrganizationSettingsV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        general:
          type: object
          properties:
            name:
              type: string
            support_email:
              type: string
              description: Correo de soporte mostrado a los clientes.
            timezone:
              type: string
              description: Zona horaria IANA (por defecto `America/Sao_Paulo`).
          required:
            - name
            - support_email
            - timezone
        records:
          type: object
          properties:
            uppercase_names:
              type: boolean
            allow_edit_public_id:
              type: boolean
            allow_edit_document:
              type: boolean
            allow_create_customers:
              type: boolean
            allow_create_portal_users:
              type: boolean
            allow_edit_portal_user_email:
              type: boolean
          required:
            - uppercase_names
            - allow_edit_public_id
            - allow_edit_document
            - allow_create_customers
            - allow_create_portal_users
            - allow_edit_portal_user_email
          description: "Opciones de registros: nombres en mayúsculas y lo que el panel permite crear o editar."
      required:
        - id
        - general
        - records
    OrganizationSettingsResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/OrganizationSettingsV1"
      required:
        - data
    OrganizationSettingsUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
        support_email:
          type: string
          format: email
        timezone:
          type: string
          description: Zona horaria IANA, p. ej. `America/Sao_Paulo`.
        crm_uppercase_names:
          type: boolean
          description: Guardar nombres en MAYÚSCULAS.
        crm_allow_edit_public_id:
          type: boolean
        crm_allow_edit_document:
          type: boolean
        crm_allow_create_customers:
          type: boolean
        crm_allow_create_portal_users:
          type: boolean
          description: Permitir crear usuarios del portal desde el panel y por importación.
        crm_allow_edit_portal_user_email:
          type: boolean
    SystemUsageV1:
      type: object
      properties:
        start_date:
          type: string
          format: date
        end_date:
          type: string
          format: date
        metrics:
          type: array
          items:
            type: object
            properties:
              metric:
                type: string
                description: Identificador de la métrica.
              current:
                type:
                  - number
                  - "null"
                description: Valor del día más reciente del período.
              peak:
                type:
                  - number
                  - "null"
                description: Mayor valor del período.
              series:
                type: array
                items:
                  type: object
                  properties:
                    date:
                      type: string
                      format: date
                    quantity:
                      type: number
                  required:
                    - date
                    - quantity
            required:
              - metric
              - current
              - peak
              - series
        last_updated_at:
          type:
            - string
            - "null"
          format: date-time
      required:
        - start_date
        - end_date
        - metrics
        - last_updated_at
    SystemUsageResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/SystemUsageV1"
      required:
        - data
    AiUsageV1:
      type: object
      properties:
        month_start:
          type: string
          format: date-time
        month_to_date:
          type: object
          properties:
            price_usd:
              type:
                - string
                - "null"
            turns:
              type: integer
            tokens:
              type: integer
          required:
            - price_usd
            - turns
            - tokens
          description: Acumulado del mes de la organización.
        courtesy:
          type: object
          properties:
            in_force:
              type: boolean
            monthly_limit_usd:
              type:
                - string
                - "null"
            consumed_usd:
              type:
                - string
                - "null"
            valid_until:
              type:
                - string
                - "null"
              format: date
          required:
            - in_force
            - monthly_limit_usd
            - consumed_usd
            - valid_until
          description: Franquicia de cortesía vigente.
        org_cap_usd:
          type:
            - string
            - "null"
          description: Tope mensual de la organización, cuando lo hay.
        credit_balance_usd:
          type: string
        next_turn:
          type: object
          properties:
            allowed:
              type: boolean
            funded_by:
              type:
                - string
                - "null"
            code:
              type:
                - string
                - "null"
          required:
            - allowed
            - funded_by
            - code
          description: Si el próximo turno de IA está permitido y quién lo financia.
        entitlement:
          type: object
          properties:
            has_plan:
              type: boolean
            monthly_limit_usd:
              type:
                - string
                - "null"
          required:
            - has_plan
            - monthly_limit_usd
        period:
          type: object
          properties:
            start_date:
              type: string
              format: date
            end_date:
              type: string
              format: date
            turns:
              type: integer
            prompt_tokens:
              type: integer
            completion_tokens:
              type: integer
            total_tokens:
              type: integer
            price_usd:
              type: string
              description: Precio en dólares, como texto decimal.
          required:
            - start_date
            - end_date
            - turns
            - prompt_tokens
            - completion_tokens
            - total_tokens
            - price_usd
          description: Totales del workspace en el período.
        by_day:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
                format: date
              turns:
                type: integer
              prompt_tokens:
                type: integer
              completion_tokens:
                type: integer
              total_tokens:
                type: integer
              price_usd:
                type: string
                description: Precio en dólares, como texto decimal.
            required:
              - date
              - turns
              - prompt_tokens
              - completion_tokens
              - total_tokens
              - price_usd
        recent:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              workspace_id:
                type:
                  - string
                  - "null"
                format: uuid
              conversation_id:
                type:
                  - string
                  - "null"
              prompt_tokens:
                type: integer
              completion_tokens:
                type: integer
              total_tokens:
                type: integer
              price_usd:
                type: string
              funded_by:
                type:
                  - string
                  - "null"
              created_at:
                type: string
                format: date-time
            required:
              - id
              - workspace_id
              - conversation_id
              - prompt_tokens
              - completion_tokens
              - total_tokens
              - price_usd
              - funded_by
              - created_at
      required:
        - month_start
        - month_to_date
        - courtesy
        - org_cap_usd
        - credit_balance_usd
        - next_turn
        - entitlement
        - period
        - by_day
        - recent
    AiUsageResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/AiUsageV1"
      required:
        - data
    RateLimitsV1:
      type: object
      properties:
        config:
          type: object
          properties:
            get_requests_per_minute:
              type: integer
            get_requests_per_hour:
              type: integer
            mutate_requests_per_minute:
              type: integer
            mutate_requests_per_hour:
              type: integer
            burst_limit:
              type: integer
            burst_window_seconds:
              type: integer
            enabled:
              type: boolean
          required:
            - get_requests_per_minute
            - get_requests_per_hour
            - mutate_requests_per_minute
            - mutate_requests_per_hour
            - burst_limit
            - burst_window_seconds
            - enabled
          description: Límites vigentes.
        has_custom_config:
          type: boolean
          description: "`true` cuando la organización tiene configuración propia."
        defaults:
          type: object
          properties:
            get_requests_per_minute:
              type: integer
            get_requests_per_hour:
              type: integer
            mutate_requests_per_minute:
              type: integer
            mutate_requests_per_hour:
              type: integer
            burst_limit:
              type: integer
            burst_window_seconds:
              type: integer
            enabled:
              type: boolean
          required:
            - get_requests_per_minute
            - get_requests_per_hour
            - mutate_requests_per_minute
            - mutate_requests_per_hour
            - burst_limit
            - burst_window_seconds
            - enabled
          description: Valores por defecto de la plataforma.
      required:
        - config
        - has_custom_config
        - defaults
    RateLimitsResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/RateLimitsV1"
      required:
        - data
    PortalUserMappingV1:
      type: object
      properties:
        entity_type_id:
          type: string
          format: uuid
        tenant_id_field_key:
          type: string
          description: Campo de la entidad que da el ID del titular del usuario.
        email_field_key:
          type: string
        name_field_key:
          type:
            - string
            - "null"
        mapped_at:
          type: string
        mapped_by_email:
          type:
            - string
            - "null"
        last_synced_at:
          type:
            - string
            - "null"
        last_status:
          type:
            - string
            - "null"
          enum:
            - completed
            - error
        last_error:
          type:
            - string
            - "null"
        last_stats:
          type:
            - object
            - "null"
          properties:
            read:
              type: integer
            users_created:
              type: integer
            users_existing:
              type: integer
            users_linked:
              type: integer
            users_retenanted:
              type: integer
            skipped:
              type: integer
          required:
            - read
            - users_created
            - users_existing
            - users_linked
            - users_retenanted
            - skipped
        cascade_tenant_ids:
          type: boolean
          description: "El origen del ID del titular cambió: la próxima sincronización lo reescribe en los usuarios existentes."
      required:
        - entity_type_id
        - tenant_id_field_key
        - email_field_key
        - name_field_key
        - mapped_at
        - mapped_by_email
        - last_synced_at
        - last_status
        - last_error
        - last_stats
        - cascade_tenant_ids
    PortalUserMappingStateV1:
      type: object
      properties:
        mapping:
          allOf:
            - $ref: "#/components/schemas/PortalUserMappingV1"
            - type:
                - object
                - "null"
        entities:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              identifier_field_key:
                type:
                  - string
                  - "null"
              owner_field_key:
                type:
                  - string
                  - "null"
              records_count:
                type: integer
              fields:
                type: array
                items:
                  type: object
                  properties:
                    key:
                      type: string
                    name:
                      type: string
                    data_type:
                      type: string
                    semantic_role:
                      type:
                        - string
                        - "null"
                  required:
                    - key
                    - name
                    - data_type
                    - semantic_role
            required:
              - id
              - name
              - identifier_field_key
              - owner_field_key
              - records_count
              - fields
          description: Entidades del workspace que pueden mapearse, con sus campos.
      required:
        - mapping
        - entities
    PortalUserMappingGetResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalUserMappingStateV1"
      required:
        - data
    PortalUserMappingSyncedV1:
      type: object
      properties:
        mapping:
          allOf:
            - $ref: "#/components/schemas/PortalUserMappingV1"
            - type:
                - object
                - "null"
        stats:
          type:
            - object
            - "null"
          properties:
            read:
              type: integer
            users_created:
              type: integer
            users_existing:
              type: integer
            users_linked:
              type: integer
            users_retenanted:
              type: integer
            skipped:
              type: integer
          required:
            - read
            - users_created
            - users_existing
            - users_linked
            - users_retenanted
            - skipped
          description: Resultado de la sincronización hecha ahora.
      required:
        - mapping
        - stats
    PortalUserMappingUpdateResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalUserMappingSyncedV1"
      required:
        - data
    PortalUserMappingDeletedV1:
      type: object
      properties:
        mapping:
          type: "null"
        deleted:
          type: boolean
      required:
        - mapping
        - deleted
    PortalUserMappingDeleteResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PortalUserMappingDeletedV1"
      required:
        - data
    PortalUserMappingUpdateRequest:
      type: object
      properties:
        entity_type_id:
          type: string
          format: uuid
          description: La entidad cuyos registros se convierten en usuarios del portal.
        tenant_id_field_key:
          type: string
          minLength: 1
          maxLength: 200
        email_field_key:
          type: string
          minLength: 1
          maxLength: 200
        name_field_key:
          type:
            - string
            - "null"
          maxLength: 200
      required:
        - entity_type_id
        - tenant_id_field_key
        - email_field_key
    AssetV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
          description: Nombre visible del archivo (por defecto, el nombre original, con la extensión).
        url:
          type: string
          description: "Enlace para quien puede abrir el archivo: la URL del storage cuando es `public`, la ruta del portal cuando es `restricted` (usuarios del portal con sesión) y la ruta del panel cuando es `private`."
        download_url:
          type: string
          description: Ruta de la API que devuelve el contenido del archivo al token, sea cual sea la visibilidad.
        visibility:
          type: string
          enum:
            - public
            - restricted
            - private
          description: "Quién puede descargarlo: `public` (cualquiera con el enlace), `restricted` (usuarios con sesión en el portal del workspace) o `private` (solo miembros del panel). Los archivos nuevos empiezan `restricted`."
        content_type:
          type: string
          example: image/png
        size_bytes:
          type: integer
          description: Tamaño en bytes.
        kind:
          type: string
          enum:
            - image
            - document
            - other
          description: "`image`, `document` u `other`, derivado del tipo de archivo."
        alt_text:
          type:
            - string
            - "null"
          description: Texto alternativo de una imagen (accesibilidad).
        source:
          type: string
          enum:
            - upload
            - chat
            - ai
          description: "Por dónde entró el archivo: `upload` (panel o API), `chat` (enviado en el chat del constructor) o `ai` (guardado por la IA del constructor)."
        created_by_email:
          type:
            - string
            - "null"
          description: Correo de quien subió el archivo, cuando se conoce.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - name
        - url
        - download_url
        - visibility
        - content_type
        - size_bytes
        - kind
        - alt_text
        - source
        - created_by_email
        - created_at
        - updated_at
    AssetResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/AssetV1"
      required:
        - data
    AssetListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/AssetV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    AssetCreateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre visible, con la extensión (obligatorio). La extensión decide el tipo aceptado cuando no viene `content_type`.
        key:
          type: string
          description: El `key` devuelto por `POST /assets/presign`, después de enviar el archivo a la URL firmada. Envíe `key` o `content_base64`, nunca ambos.
        content_base64:
          type: string
          description: "El contenido del archivo en base64, para archivos pequeños: el cuerpo de la solicitud tiene un límite de 2 MB (cerca de 1,5 MB de archivo). Para archivos mayores, use `POST /assets/presign`."
        content_type:
          type: string
          description: "Tipo MIME. Si se omite, se deduce de la extensión. Aceptados: imágenes PNG, JPEG, GIF, WebP y AVIF; PDF, texto, CSV, Markdown, JSON, XML, Office y ZIP. SVG y HTML no se aceptan."
        alt_text:
          type: string
          description: Texto alternativo de una imagen (accesibilidad).
        visibility:
          type: string
          enum:
            - public
            - restricted
            - private
          description: "Quién puede descargarlo: `public` (cualquiera con el enlace), `restricted` (usuarios con sesión en el portal del workspace) o `private` (solo miembros del panel). Los archivos nuevos empiezan `restricted`."
      required:
        - name
    AssetUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre visible del archivo (por defecto, el nombre original, con la extensión).
        alt_text:
          type:
            - string
            - "null"
          description: Texto alternativo de una imagen. Envíe `null` para limpiarlo.
        visibility:
          type: string
          enum:
            - public
            - restricted
            - private
          description: "Quién puede descargarlo: `public` (cualquiera con el enlace), `restricted` (usuarios con sesión en el portal del workspace) o `private` (solo miembros del panel). Los archivos nuevos empiezan `restricted`."
    AssetPresignRequest:
      type: object
      properties:
        filename:
          type: string
          description: Nombre del archivo con la extensión.
        content_type:
          type: string
          description: "Tipo MIME. Si se omite, se deduce de la extensión. Aceptados: imágenes PNG, JPEG, GIF, WebP y AVIF; PDF, texto, CSV, Markdown, JSON, XML, Office y ZIP. SVG y HTML no se aceptan."
        size:
          type: integer
          exclusiveMinimum: 0
          description: Tamaño exacto, en bytes, del archivo que se enviará (máximo 25 MB).
      required:
        - filename
        - size
    AssetPresignResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            url:
              type: string
              description: URL firmada y de corta duración a la que enviar el archivo con `PUT`.
            method:
              type: string
              enum:
                - PUT
            headers:
              type: object
              additionalProperties:
                type: string
              description: Cabeceras que el `PUT` debe llevar exactamente como están.
            key:
              type: string
              description: "Clave del archivo en el storage: envíela a `POST /assets` para registrarlo."
            content_type:
              type: string
              description: Tipo MIME resuelto para el archivo.
          required:
            - url
            - method
            - headers
            - key
            - content_type
      required:
        - data
    DashboardUserUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/DashboardUserV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    DashboardUserUpsertRequest:
      type: object
      properties:
        email:
          type: string
          format: email
          description: Correo del usuario. Además de campo del recurso, sirve como clave natural de búsqueda.
        name:
          type: string
          description: Nombre del usuario (opcional — el usuario puede completarlo al primer acceso).
        external_id:
          type: string
          description: "Identificador externo del usuario, guardado como atributo del miembro. No define la identidad del usuario: siempre se resuelve por `email`."
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs de roles (`team_roles`) a asignar al usuario. Debe contener al menos un ítem.
        permissions:
          type: array
          items:
            type: string
          description: Permisos ad-hoc adicionales (además de los heredados de los roles). Acepta los mismos slugs de permisos.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        id:
          type: string
          format: uuid
          description: UUID del registro. Se usa solo para localizarlo — nunca se guarda.
        public_id:
          type: string
          format: uuid
          description: UUID público del registro, usado para localizarlo.
    TeamRoleUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/TeamRoleV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    TeamRoleUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre del rol (mostrado en la interfaz).
        slug:
          type: string
          pattern: ^[a-z][a-z0-9_]*$
          description: "Slug estable usado para referenciar el rol (ej.: `support_manager`)."
          example: portal_manager
        description:
          type: string
          description: Descripción opcional de lo que concede el rol.
        permissions:
          type: array
          items:
            type: string
          description: Lista de slugs de permisos concedidos por el rol.
        is_active:
          type: boolean
          description: Indica si el rol está activo y puede ser asignado.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        id:
          type: string
          format: uuid
          description: UUID del registro. Se usa solo para localizarlo — nunca se guarda.
        public_id:
          type: string
          format: uuid
          description: UUID público del registro, usado para localizarlo.
  parameters: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: "Envía la cabecera `Authorization: Bearer <jwt>`. El token es un access token RS256 emitido por el Authorization Server de Kobana (`account.kobana.com.br`), con `aud` igual a `https://api.dashboards.kobana.com.br` y `exp` obligatoria. El claim `org` (la cuenta Kobana) es lo que acota los datos y también es obligatorio; `sub` es la **persona** y queda para auditoría. Esta API solo verifica tokens — no emite ninguno. El claim `scope` también se verifica: un `GET` exige `read`, `write` o `all`, y cualquier otro método exige `write` o `all` — si no, la respuesta es `403 insufficient_scope`, con `{ required, granted }` en `details`. Un token emitido a una **persona** (`src` `user` u `oauth`) también queda limitado a lo que ella puede hacer en el panel: la operación exige el permiso correspondiente de su rol (si no, `403 insufficient_permission`, con `{ required }` en `details`), y quien no es miembro activo de la organización es rechazado. Un token de persona cuyo `sub` la app no logra identificar devuelve `401 invalid_token`. Los tokens de máquina (`src` `system` o `api`) actúan por la organización."
paths:
  /v1/organization:
    get:
      tags:
        - Organización
      summary: Obtener organización actual
      description: Devuelve los datos de la organización a la que pertenece el token autenticado. No hay parámetro `:id` — la organización siempre se resuelve a partir de la clave de la API.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Detalle de la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-organization
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    patch:
      tags:
        - Organización
      summary: Actualizar organización actual
      description: Actualiza el perfil de la organización autenticada. Solo los campos a continuación pueden modificarse — la identidad (`id`, `external_id`, `status`) no es modificable por este endpoint.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/OrganizationUpdateRequest"
      responses:
        "200":
          description: Organización actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-organization
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/me:
    get:
      tags:
        - Organización
      summary: Identidad del token actual
      description: "Devuelve quién está detrás del token Bearer: la persona (`user`, `null` para un token de máquina), la organización y los scopes, el nivel de acceso y la expiración del propio token. Sirve para validar la credencial configurada en una integración. Nunca devuelve el token, hashes ni claves."
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Identidad del token autenticado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MeResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-me
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_users:
    get:
      tags:
        - Usuarios del Portal
      summary: Listar usuarios del portal
      description: Devuelve los usuarios del portal del workspace, con paginación. Los campos sensibles (contraseña, tokens) nunca se exponen.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Restringe a los usuarios de un ID del titular (comparación exacta).
          required: false
          name: tenant_id
          in: query
        - schema:
            type: string
            enum:
              - active
              - pending_verification
              - pending_invitation
              - suspended
              - locked
            description: "Filtra por estado: `active`, `pending_invitation`, `pending_verification`, `suspended` o `locked`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Busca por fragmento del correo.
          required: false
          name: email
          in: query
        - schema:
            type: string
            description: Filtra por el `external_id` exacto.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Filtra por `sso_only` (`true` o `false`).
          required: false
          name: sso_only
          in: query
        - schema:
            type: string
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            description: Último acceso a partir de esta fecha (ISO 8601).
          required: false
          name: last_login_after
          in: query
        - schema:
            type: string
            description: Último acceso hasta esta fecha (ISO 8601).
          required: false
          name: last_login_before
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por UUID de la persona asociada.
          required: false
          name: person_id
          in: query
        - schema:
            type: string
            description: Filtra por CPF/CNPJ de la persona (coincidencia exacta).
          required: false
          name: person_document_number
          in: query
        - schema:
            type: string
            description: Filtra por nombre de la persona (búsqueda parcial, sin distinción de mayúsculas).
          required: false
          name: person_name_contains
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Lista paginada de usuarios del portal.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-users
    post:
      tags:
        - Usuarios del Portal
      summary: Crear (invitar) usuario del portal
      description: Crea el usuario en el workspace con estado `pending_invitation` y envía el correo de invitación. La invitación expira en 7 días.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalUserCreateRequest"
      responses:
        "201":
          description: Invitación creada y correo encolado para envío.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe un usuario o invitación para este correo en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-users
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_users/invite:
    post:
      tags:
        - Usuarios del Portal
      summary: Invitar usuario del portal (verbo)
      description: Equivalente a `POST /portal_users`. Disponible como ruta de verbo para SDKs que prefieren URLs descriptivas.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalUserCreateRequest"
      responses:
        "201":
          description: Invitación creada y correo encolado para envío.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe un usuario o invitación para este correo en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-users-invite
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_users/{id}:
    get:
      tags:
        - Usuarios del Portal
      summary: Obtener usuario del portal
      description: El parámetro `{id}` acepta el UUID o el `external_id` del usuario.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Detalle del usuario del portal.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-users-id
    patch:
      tags:
        - Usuarios del Portal
      summary: Actualizar usuario del portal
      description: "Actualiza `email`, `tenant_id`, `external_id`, `sso_only`, `status` y `custom_metadata`. Transiciones de estado permitidas: `active` ↔ `suspended`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalUserUpdateRequest"
      responses:
        "200":
          description: Usuario actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe un usuario o invitación para este correo en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-portal-users-id
    delete:
      tags:
        - Usuarios del Portal
      summary: Eliminar usuario del portal
      description: Las invitaciones pendientes se eliminan definitivamente; los demás usuarios se suspenden.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Confirmación de eliminación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-portal-users-id
  /v1/portal_users/{id}/email-preview:
    get:
      tags:
        - Usuarios del Portal
      summary: Previsualizar correo del usuario del portal
      description: Devuelve el asunto y el mensaje del correo de invitación o verificación que se enviaría al usuario, sin disparar el envío. Disponible solo para usuarios `pending_invitation` o `pending_verification`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Previsualización del correo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserEmailPreviewResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-users-id-email-preview
  /v1/portal_users/{id}/resend:
    post:
      tags:
        - Usuarios del Portal
      summary: Reenviar correo de invitación o verificación
      description: Reenvía el correo de invitación (para `pending_invitation`, con rotación de token) o de verificación (para `pending_verification`). Otros estados devuelven 400.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Correo reenviado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserResendResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-users-id-resend
  /v1/dashboard_users:
    get:
      tags:
        - Administración de la Cuenta
      summary: Listar usuarios del dashboard
      description: Devuelve una lista paginada de los usuarios del dashboard (miembros del equipo) de la organización actual.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Búsqueda textual por nombre o correo.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - all
              - active
              - pending_invitation
              - suspended
            description: "Filtra por estado: `all` (por defecto), `active`, `pending_invitation` o `suspended`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Filtra por los usuarios que tienen el rol indicado (slug del rol).
          required: false
          name: role
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Lista paginada de usuarios del dashboard.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-dashboard-users
    post:
      tags:
        - Administración de la Cuenta
      summary: Invitar usuario del dashboard
      description: Invita a un nuevo miembro al equipo de la organización. Es obligatorio informar `email` y al menos un rol en `role_ids`. El usuario recibe una invitación por correo y entra con estado `pending_invitation`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DashboardUserCreateRequest"
      responses:
        "201":
          description: Usuario invitado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Datos inválidos. Con el código `IDENTITY_CONFLICT`, el `external_id` informado es el identificador de otra identidad, con otro correo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-dashboard-users
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    put:
      tags:
        - Administración de la Cuenta
      summary: Crea o actualiza un usuario del panel
      description: Localiza al usuario por `id`, `public_id`, `external_id` o `email` — este último es único por organización. Si lo encuentra, lo actualiza; si no, lo crea y devuelve `201`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DashboardUserUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserUpsertResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Datos inválidos. Con el código `IDENTITY_CONFLICT`, el `external_id` informado es el identificador de otra identidad, con otro correo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-dashboard-users
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/dashboard_users/{id}:
    get:
      tags:
        - Administración de la Cuenta
      summary: Obtener usuario del dashboard
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del usuario del dashboard.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Detalle del usuario del dashboard.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-dashboard-users-id
    patch:
      tags:
        - Administración de la Cuenta
      summary: Actualizar usuario del dashboard
      description: Actualiza el nombre, la foto, el estado, los permisos y/o los roles del usuario. Solo se modifican los campos enviados.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del usuario del dashboard.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DashboardUserUpdateRequest"
      responses:
        "200":
          description: Usuario actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-dashboard-users-id
    delete:
      tags:
        - Administración de la Cuenta
      summary: Eliminar usuario del dashboard
      description: Elimina al usuario del dashboard de la organización. Acción irreversible — el usuario debe ser invitado de nuevo para recuperar el acceso.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del usuario del dashboard.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Usuario eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-dashboard-users-id
  /v1/team_roles:
    get:
      tags:
        - Administración de la Cuenta
      summary: Listar roles del equipo
      description: Devuelve la lista paginada de roles configurados para el equipo de la organización. Incluye tanto roles de sistema (`is_system = true`) como roles personalizados.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Búsqueda textual por nombre o slug.
          required: false
          name: search
          in: query
        - schema:
            type:
              - boolean
              - "null"
            description: Filtra por roles activos (`true`) o inactivos (`false`).
          required: false
          name: is_active
          in: query
        - schema:
            type:
              - boolean
              - "null"
            description: Filtra por roles de sistema (`true`) o personalizados (`false`).
          required: false
          name: is_system
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Lista paginada de roles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-team-roles
    post:
      tags:
        - Administración de la Cuenta
      summary: Crear rol personalizado
      description: Crea un rol personalizado. El `slug` debe empezar con una letra minúscula y contener solo letras minúsculas, dígitos y `_`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TeamRoleCreateRequest"
      responses:
        "201":
          description: Rol creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-team-roles
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    put:
      tags:
        - Administración de la Cuenta
      summary: Crea o actualiza un rol de equipo
      description: Localiza el rol por `id`, `public_id` o `external_id`. El `slug` no tiene restricción de unicidad y por lo tanto **no** identifica un registro. Si lo encuentra, lo actualiza; si no, lo crea y devuelve `201`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TeamRoleUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleUpsertResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-team-roles
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/team_roles/{id}:
    get:
      tags:
        - Administración de la Cuenta
      summary: Obtener rol
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del rol.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Detalle del rol.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-team-roles-id
    patch:
      tags:
        - Administración de la Cuenta
      summary: Actualizar rol
      description: Actualiza los campos del rol. Solo se modifican los campos enviados. Los roles de sistema tienen restricciones adicionales.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del rol.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TeamRoleUpdateRequest"
      responses:
        "200":
          description: Rol actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TeamRoleResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-team-roles-id
    delete:
      tags:
        - Administración de la Cuenta
      summary: Eliminar rol
      description: Realiza soft delete del rol. Los roles de sistema (`is_system = true`) no pueden eliminarse.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del rol.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Rol eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-team-roles-id
  /v1/workspaces:
    get:
      tags:
        - Workspaces
      summary: Listar workspaces
      description: Lista los workspaces de la organización que usted puede abrir, con su rol en cada uno — los mismos del selector del dashboard. Un token de máquina ve todos los workspaces de la organización. No requiere `X-Workspace-Id`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Fragmento del nombre del workspace, sin distinguir mayúsculas.
          required: false
          name: search
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de workspaces.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-workspaces
    post:
      tags:
        - Workspaces
      summary: Crear workspace
      description: "Crea un workspace vacío en la organización. La persona del token pasa a ser su dueña. Creado por un token de máquina, el workspace queda sin dueño: los dueños de la organización lo reciben en su próximo inicio de sesión, y `PUT /dashboard_users/{id}/workspaces` lo concede a otros miembros."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WorkspaceWriteRequest"
      responses:
        "201":
          description: Workspace creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-workspaces
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/workspaces/import:
    post:
      tags:
        - Workspaces
      summary: Importar workspace
      description: Restaura un archivo de `GET /workspaces/{id}/export` en un workspace NUEVO, cuyo dueño es la persona del token. Responde lo que no se pudo traer de vuelta (`warnings`) para terminarlo a mano. Requiere un token de persona (un token de máquina recibe 403) con los permisos de crear workspaces, configurar el portal y crear fuentes de datos. Las entidades del archivo pasan por las mismas validaciones que al crearlas una a una (claves, expresiones, límite de campos del workspace). El cuerpo está limitado a 2 MB.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WorkspaceImportRequest"
      responses:
        "201":
          description: Workspace importado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceImportResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El archivo no es una exportación de workspace válida (`INVALID_WORKSPACE_FILE`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-workspaces-import
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/workspaces/{id}:
    get:
      tags:
        - Workspaces
      summary: Consultar workspace
      description: Devuelve un workspace que usted puede abrir. Un workspace sin acceso concedido responde 404.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del workspace.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Workspace encontrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-workspaces-id
    patch:
      tags:
        - Workspaces
      summary: Renombrar workspace
      description: Renombra el workspace. Solo los dueños del workspace pueden (403 para un miembro común).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del workspace.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WorkspaceWriteRequest"
      responses:
        "200":
          description: Workspace renombrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-workspaces-id
    delete:
      tags:
        - Workspaces
      summary: Eliminar workspace
      description: "Elimina el workspace (eliminación lógica), solo para sus dueños: el portal deja de estar disponible, los conectores dejan de sincronizar y los miembros pierden el acceso. El último workspace de la organización no puede eliminarse."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del workspace.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Workspace eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Es el último workspace de la organización (`WORKSPACE_LAST`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-workspaces-id
  /v1/workspaces/{id}/usage:
    get:
      tags:
        - Workspaces
      summary: Consultar el contenido del workspace
      description: Cuenta lo que la eliminación del workspace ocultaría — el mismo resumen del diálogo de eliminación del dashboard.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del workspace.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Conteos del workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceUsageResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-workspaces-id-usage
  /v1/workspaces/{id}/export:
    get:
      tags:
        - Workspaces
      summary: Exportar workspace
      description: Descarga la configuración del workspace (constructor del portal, acceso y ajustes del portal, mapeo de usuarios, conectores y entidades) como un archivo JSON, solo para sus dueños. Los secretos y los datos quedan fuera. La respuesta es el propio archivo, sin envoltorio `data`; envíelo como `data` a `POST /workspaces/import`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del workspace.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: "Archivo de exportación (`Content-Disposition: attachment`)."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceExportFile"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-workspaces-id-export
  /v1/dashboard_users/{id}/workspaces:
    get:
      tags:
        - Administración de la Cuenta
      summary: Consultar los workspaces de un miembro
      description: Lista todos los workspaces de la organización, marcando a los que el miembro accede — también es la lista de lo que se puede conceder.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del miembro del equipo (usuario del dashboard).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Workspaces de la organización con el acceso del miembro.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceGrantListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-dashboard-users-id-workspaces
    put:
      tags:
        - Administración de la Cuenta
      summary: Definir los workspaces de un miembro
      description: Reemplaza el conjunto de workspaces del miembro. Nadie cambia su propio acceso (400), solo un dueño cambia el acceso de un dueño, y solo un dueño concede o revoca un workspace al que él mismo no accede (403). Un token de máquina puede conceder cualquier workspace, pero nunca cambia el acceso de un dueño. Quitar al último dueño de un workspace responde 403.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del miembro del equipo (usuario del dashboard).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WorkspaceGrantReplaceRequest"
      responses:
        "200":
          description: Workspaces de la organización con el acceso del miembro.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WorkspaceGrantListResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-dashboard-users-id-workspaces
  /v1/dashboard_users/{id}/resend:
    post:
      tags:
        - Administración de la Cuenta
      summary: Reenviar invitación de miembro
      description: Reenvía el correo de invitación, con un nuevo enlace de acceso, a un miembro cuya invitación sigue pendiente. Limitado a 5 envíos por hora por destinatario (429 por encima de eso).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del miembro del equipo (usuario del dashboard).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Invitación reenviada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DashboardUserResendResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El miembro no tiene una invitación pendiente (`INVALID_STATUS`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "502":
          description: No se pudo enviar el correo (`EMAIL_ERROR`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-dashboard-users-id-resend
  /v1/permissions:
    get:
      tags:
        - Administración de la Cuenta
      summary: Listar permisos
      description: Catálogo de los permisos del dashboard que un miembro o un rol del equipo puede tener, agrupados por recurso — el vocabulario de `permissions` en `/dashboard_users` y `/team_roles`.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Grupos de permisos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PermissionCatalogResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-permissions
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources:
    get:
      tags:
        - Fuentes de Datos
      summary: Listar fuentes de datos
      description: "Fuentes de datos del workspace — APIs OpenAPI, servidores MCP y bases de solo lectura —, de las más nuevas a las más antiguas. Los secretos nunca se devuelven. Para crear una fuente, use la ruta de su tipo: `/data_sources/openapi`, `/mcp`, `/database` o `/catalog`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de fuentes de datos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-sources
  /v1/data_sources/catalog:
    get:
      tags:
        - Fuentes de Datos
      summary: Listar productos del catálogo Kobana
      description: Productos Kobana que se pueden conectar como fuente de datos solo con un token. Lista completa, sin paginación.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Productos del catálogo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceCatalogResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-sources-catalog
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Fuentes de Datos
      summary: Conectar producto Kobana
      description: Guarda una fuente OpenAPI a partir de la spec del producto incluida en la aplicación y prueba la conexión.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceCatalogConnectRequest"
      responses:
        "201":
          description: Fuente creada, con el resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceCreatedResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe una fuente de datos con este nombre en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-catalog
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/openapi:
    post:
      tags:
        - Fuentes de Datos
      summary: Crear fuente OpenAPI
      description: Guarda una API descrita por una spec OpenAPI, importa sus operaciones y prueba la conexión. La spec va como texto en `spec`; el certificado mTLS, en base64 en `certificate`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceOpenApiCreateRequest"
      responses:
        "201":
          description: Fuente creada, con el resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceCreatedResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe una fuente de datos con este nombre en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-openapi
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/openapi/analyze:
    post:
      tags:
        - Fuentes de Datos
      summary: Analizar spec OpenAPI
      description: Lee la spec y devuelve lo que se importaría — título, servidores, esquemas de seguridad, autenticación sugerida y operaciones — sin guardar nada.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceSpecRequest"
      responses:
        "200":
          description: Análisis de la spec.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceSpecAnalysisResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-openapi-analyze
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/mcp:
    post:
      tags:
        - Fuentes de Datos
      summary: Crear fuente MCP
      description: Guarda un servidor MCP. Sin OAuth, conecta y descubre las tools al momento; con OAuth, devuelve `authorization_url`, que una persona con sesión en el dashboard debe abrir en el navegador para terminar.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceMcpCreateRequest"
      responses:
        "201":
          description: Fuente creada, con el resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceMcpCreatedResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe una fuente de datos con este nombre en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-mcp
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/database:
    post:
      tags:
        - Fuentes de Datos
      summary: Crear fuente de base de datos
      description: Guarda una base de solo lectura (PostgreSQL, MySQL, MariaDB, SQL Server o MongoDB), conecta y cataloga sus tablas o colecciones.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceDatabaseCreateRequest"
      responses:
        "201":
          description: Fuente creada, con el resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceCreatedResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe una fuente de datos con este nombre en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-database
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/test:
    post:
      tags:
        - Fuentes de Datos
      summary: Probar conexión antes de guardar
      description: Prueba una conexión aún no guardada. Informe `kind` (`openapi`, `mcp`, `database` o `catalog`) y el cuerpo de la ruta de creación correspondiente. No se persiste nada.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceDraftTestRequest"
      responses:
        "200":
          description: Resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceDraftTestResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-test
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_sources/{id}:
    get:
      tags:
        - Fuentes de Datos
      summary: Consultar fuente de datos
      description: La fuente de datos y sus operaciones (endpoints, tools o tablas que puede leer).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Fuente de datos con sus operaciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceDetailResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-sources-id
    patch:
      tags:
        - Fuentes de Datos
      summary: Actualizar fuente de datos
      description: Actualiza nombre, `is_active` y los campos de conexión del tipo de la fuente. Los campos secretos en blanco mantienen los guardados. Una fuente OpenAPI recibe un nuevo certificado en `certificate`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceUpdateRequest"
      responses:
        "200":
          description: Fuente de datos actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Ya existe una fuente de datos con este nombre en el workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-data-sources-id
    delete:
      tags:
        - Fuentes de Datos
      summary: Eliminar fuente de datos
      description: Elimina la fuente, sus operaciones y la agenda de sincronización. Las entidades alimentadas por ella dejan de sincronizar. No se puede deshacer.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Fuente eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-data-sources-id
  /v1/data_sources/{id}/test:
    post:
      tags:
        - Fuentes de Datos
      summary: Probar fuente de datos
      description: Prueba la fuente guardada y registra el resultado (estado, último error). En un servidor MCP, también actualiza la lista de tools.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Resultado de la prueba de conexión.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceTestResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-id-test
  /v1/data_sources/{id}/sync:
    post:
      tags:
        - Fuentes de Datos
      summary: Sincronizar fuente de datos
      description: Encola la sincronización de todas las entidades alimentadas por la fuente. La ejecución es asíncrona.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceSyncRequest"
      responses:
        "202":
          description: Sincronización encolada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceSyncResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: "Límite superado: el de solicitudes de la API, o el de sincronizaciones encoladas por la organización (60 por hora, sumando todas las fuentes de datos) — código `rate_limited`. Espere el tiempo indicado en `Retry-After` e intente de nuevo."
          headers:
            Retry-After:
              description: Segundos hasta que la organización pueda encolar otra sincronización.
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-id-sync
  /v1/data_sources/{id}/schedule:
    put:
      tags:
        - Fuentes de Datos
      summary: Agendar sincronización de la fuente
      description: "Define con qué frecuencia sincroniza la fuente: `{ cron, timezone }`, o `{ cron: null }` para solo bajo demanda. Devuelve las próximas ejecuciones."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceScheduleRequest"
      responses:
        "200":
          description: Agenda guardada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceScheduleResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-data-sources-id-schedule
  /v1/data_sources/{id}/spec:
    put:
      tags:
        - Fuentes de Datos
      summary: Reemplazar spec de la fuente
      description: "Reemplaza la spec OpenAPI y resincroniza las operaciones: las que mantienen la clave mantienen su configuración; las que desaparecieron de la spec se eliminan."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceSpecRequest"
      responses:
        "200":
          description: Spec reemplazada, con los avisos del análisis.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceSpecResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-data-sources-id-spec
  /v1/data_sources/{id}/authorize:
    post:
      tags:
        - Fuentes de Datos
      summary: Autorizar fuente MCP
      description: Reinicia la autorización OAuth de un servidor MCP. Devuelve `authorization_url` para que una persona con sesión en el dashboard la abra en el navegador, o `null` y la prueba de conexión cuando los tokens guardados aún funcionan.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: URL de autorización o resultado de la prueba.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceAuthorizeResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-sources-id-authorize
  /v1/data_sources/{id}/logs:
    get:
      tags:
        - Fuentes de Datos
      summary: Listar log de solicitudes de la fuente
      description: Llamadas que hizo la fuente (solicitudes HTTP, consultas a la base), de las más nuevas a las más antiguas, sin cabeceras ni cuerpos.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Método HTTP (GET, POST…).
          required: false
          name: method
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: "`true` solo las llamadas exitosas, `false` solo las que fallaron."
          required: false
          name: success
          in: query
        - schema:
            type: string
            description: Fragmento del endpoint, sin distinguir mayúsculas.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: date
            description: Desde este día (YYYY-MM-DD, UTC), inclusive.
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            format: date
            description: Hasta este día (YYYY-MM-DD, UTC), inclusive.
          required: false
          name: date_to
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página del log de solicitudes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceRequestLogListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-sources-id-logs
  /v1/data_sources/{id}/logs/{log_id}:
    get:
      tags:
        - Fuentes de Datos
      summary: Consultar solicitud de la fuente
      description: "Una llamada completa: cabeceras y cuerpos de la solicitud y de la respuesta, con secretos enmascarados."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: ID de la entrada del log de solicitudes.
          required: true
          name: log_id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Entrada del log de solicitudes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceRequestLogResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-sources-id-logs-log-id
  /v1/data_sources/{id}/operations/{operation_id}:
    patch:
      tags:
        - Fuentes de Datos
      summary: Activar o desactivar operación de la fuente
      description: Activa o desactiva una operación de la fuente (`enabled`). Las operaciones desactivadas no alimentan entidades.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la fuente de datos (UUID).
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: ID de la operación de la fuente.
          required: true
          name: operation_id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataSourceOperationUpdateRequest"
      responses:
        "200":
          description: Operación actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataSourceOperationResponse"
        "400":
          description: Cuerpo que no es JSON, o campo con tipo incorrecto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-data-sources-id-operations-operation-id
  /v1/entities:
    get:
      tags:
        - Entidades
      summary: Listar entidades
      description: Todas las entidades del workspace, con campos, origen y estado de la sincronización, ordenadas por nombre. Sin paginación.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Entidades del workspace.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Entidades
      summary: Crear entidad
      description: Registra una entidad a partir de una operación de lectura (o consulta SQL) de la fuente de datos con los campos elegidos, y encola la primera sincronización completa.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityCreateRequest"
      responses:
        "201":
          description: Entidad creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "Conflicto: clave ya usada en el workspace, o la entidad es leída por una relación."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/entities/preview:
    post:
      tags:
        - Entidades
      summary: Vista previa de un origen
      description: Llama a la operación de lectura elegida (o ejecuta la consulta SQL) y devuelve la muestra con la entidad inferida de ella. No se guarda nada; la llamada queda en el registro de solicitudes del conector.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityPreviewRequest"
      responses:
        "200":
          description: Muestra y entidad inferida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityPreviewResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities-preview
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/entities/join:
    post:
      tags:
        - Entidades
      summary: Crear entidad de relación
      description: Registra una entidad que relaciona otras dos (join) con los campos elegidos de cada una, y encola la primera sincronización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityJoinRequest"
      responses:
        "201":
          description: Entidad creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "Conflicto: clave ya usada en el workspace, o la entidad es leída por una relación."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities-join
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/entities/join/preview:
    post:
      tags:
        - Entidades
      summary: Vista previa de una relación
      description: Cómo coinciden dos entidades en los campos indicados (recuentos) y las primeras filas combinadas, antes de guardar la relación. Lee solo los registros ya sincronizados.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityJoinSpecV1"
      responses:
        "200":
          description: Vista previa de la relación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityJoinPreviewResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities-join-preview
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/entities/{id}:
    get:
      tags:
        - Entidades
      summary: Consultar entidad
      description: Una entidad con campos, origen, modo de sincronización, campo del titular y estado de la sincronización.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La entidad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id
    patch:
      tags:
        - Entidades
      summary: Actualizar entidad
      description: Nombre, clave, campos especiales, paginación, filtros y modo de la sincronización, y la lista de campos (emparejada por clave). Cuando cambia el mapeo, los registros se vuelven a leer.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityUpdateRequest"
      responses:
        "200":
          description: Entidad actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "Conflicto: clave ya usada en el workspace, o la entidad es leída por una relación."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-entities-id
    delete:
      tags:
        - Entidades
      summary: Eliminar entidad
      description: Elimina (soft delete) la entidad y sus campos. Rechazado (409) mientras una entidad de relación la lee.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Entidad eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "Conflicto: clave ya usada en el workspace, o la entidad es leída por una relación."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-entities-id
  /v1/entities/{id}/join:
    put:
      tags:
        - Entidades
      summary: Modificar relación
      description: Cambia la relación de una entidad join y los campos que trae, y vuelve a leer sus registros. 422 cuando la entidad no es una relación.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityJoinRequest"
      responses:
        "200":
          description: Entidad actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "Conflicto: clave ya usada en el workspace, o la entidad es leída por una relación."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-entities-id-join
  /v1/entities/{id}/records:
    get:
      tags:
        - Entidades
      summary: Consultar registros
      description: Los registros sincronizados de la entidad, con filtro por campo, ordenación y paginación por `limit`/`offset` (la misma consulta de los bloques del portal).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            maximum: 200
            description: Registros por llamada (por defecto 50, máximo 200).
            example: 50
          required: false
          name: limit
          in: query
        - schema:
            type:
              - integer
              - "null"
            minimum: 0
            maximum: 10000
            description: Cuántos registros omitir.
            example: 0
          required: false
          name: offset
          in: query
        - schema:
            type: string
            description: Claves de campo con dirección opcional, separadas por coma (`campo:desc,otro`); `asc` por defecto.
            example: due_date:desc,name
          required: false
          name: sort
          in: query
        - schema:
            type: string
            description: 'Objeto JSON de condiciones por campo: `{"campo": valor}` o `{"campo": {"gte": 10}}`. Operadores: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `contains`, `is_null`.'
            example: '{"status":"open","amount":{"gte":100}}'
          required: false
          name: filter
          in: query
        - schema:
            type: string
            format: uuid
            description: "ID de un usuario del portal: solo sus registros, como los muestra el portal (en una entidad `on_access`, sincroniza ese titular antes)."
          required: false
          name: preview_as
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Registros de la entidad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityRecordsQueryResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-records
    delete:
      tags:
        - Entidades
      summary: Limpiar registros
      description: Elimina todos los registros sincronizados de la entidad y reinicia el estado de la sincronización, para que la próxima lea el origen desde cero.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Registros eliminados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityRecordsClearedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-entities-id-records
  /v1/entities/{id}/records/{record_id}:
    get:
      tags:
        - Entidades
      summary: Consultar registro
      description: Un registro sincronizado — valores por campo y el registro tal como lo envió el origen — con su entidad.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del registro sincronizado — el `_record.id` de un registro listado.
          required: true
          name: record_id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El registro y su entidad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityRecordResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-records-record-id
  /v1/entities/{id}/aggregate:
    get:
      tags:
        - Entidades
      summary: Agregar registros
      description: Recuento, suma, promedio, mínimo o máximo sobre los registros sincronizados, opcionalmente agrupados por un campo — lo que muestran los bloques de KPI y gráfico.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: string
            enum:
              - count
              - sum
              - avg
              - min
              - max
            description: "Agregación: `count` (por defecto), `sum`, `avg`, `min` o `max`."
          required: false
          name: op
          in: query
        - schema:
            type: string
            description: Clave del campo agregado (obligatoria excepto en `count`; numérico en `sum`/`avg`).
          required: false
          name: field
          in: query
        - schema:
            type: string
            description: Clave del campo por el cual agrupar.
          required: false
          name: group_by
          in: query
        - schema:
            type: string
            description: 'Objeto JSON de condiciones por campo: `{"campo": valor}` o `{"campo": {"gte": 10}}`. Operadores: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `contains`, `is_null`.'
            example: '{"status":"open","amount":{"gte":100}}'
          required: false
          name: filter
          in: query
        - schema:
            type: string
            format: uuid
            description: "ID de un usuario del portal: solo sus registros, como los muestra el portal (en una entidad `on_access`, sincroniza ese titular antes)."
          required: false
          name: preview_as
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Resultado de la agregación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityAggregateResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-aggregate
  /v1/entities/{id}/usage:
    get:
      tags:
        - Entidades
      summary: Uso de la entidad
      description: Las páginas del portal (borrador y publicada) cuyos bloques leen la entidad — lo que se rompe si se elimina o cambia su clave.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Páginas que usan la entidad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityUsageResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-usage
  /v1/entities/{id}/logs:
    get:
      tags:
        - Entidades
      summary: Registro de la sincronización
      description: "Las llamadas que la sincronización de la entidad hizo al conector, de las más nuevas a las más antiguas: el registro de solicitudes del conector restringido a la entidad."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Método HTTP de la llamada, como `GET`.
          required: false
          name: method
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Solo llamadas exitosas (`true`) o fallidas (`false`).
          required: false
          name: success
          in: query
        - schema:
            type: string
            description: Parte del endpoint llamado.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: date
            description: Primer día (AAAA-MM-DD).
            example: 2026-01-01
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            format: date
            description: Último día, inclusive (AAAA-MM-DD).
            example: 2026-01-31
          required: false
          name: date_to
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Llamadas de la sincronización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntitySyncLogListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-logs
  /v1/entities/{id}/logs/{log_id}:
    get:
      tags:
        - Entidades
      summary: Consultar llamada de la sincronización
      description: Una llamada de la sincronización de la entidad, completa (secretos enmascarados).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la llamada en el registro de solicitudes.
          required: true
          name: log_id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La llamada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntitySyncLogResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-logs-log-id
  /v1/entities/{id}/sync:
    post:
      tags:
        - Entidades
      summary: Sincronizar entidad
      description: "Encola una sincronización de la entidad y responde 202 con el ID; el avance está en `GET /entities/{id}/sync`. Una entidad `on_access` no tiene sincronización general (422): use `POST /entities/{id}/tenant_syncs`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: string
            enum:
              - "true"
              - "1"
            description: "`true` (o `1`) vuelve a leer todo y descarta lo que el origen ya no tiene; sin él, la sincronización es incremental cuando el origen lo permite."
          required: false
          name: full
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "202":
          description: Sincronización encolada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntitySyncQueuedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities-id-sync
    get:
      tags:
        - Entidades
      summary: Estado de la sincronización
      description: "Dónde está la sincronización de la entidad: estado, último error, últimas sincronizaciones, total de registros y estadísticas."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Estado de la sincronización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntitySyncStateResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-sync
  /v1/entities/{id}/tenant_syncs:
    get:
      tags:
        - Entidades
      summary: Sincronizaciones por titular
      description: "En una entidad `on_access`: dónde está la sincronización de cada titular, de los accedidos más recientemente a los más antiguos."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            enum:
              - queued
              - running
              - completed
              - error
            description: Estado de la sincronización del titular.
          required: false
          name: status
          in: query
        - schema:
            type: string
            maxLength: 200
            description: Parte del Tenant ID.
          required: false
          name: search
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Sincronizaciones de los titulares.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityTenantSyncListResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-entities-id-tenant-syncs
    post:
      tags:
        - Entidades
      summary: Sincronizar un titular
      description: Encola ahora la sincronización de un titular de una entidad `on_access`. 404 cuando ningún usuario del portal tiene ese Tenant ID; 422 cuando la entidad no es `on_access`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entidad.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EntityTenantSyncRequest"
      responses:
        "202":
          description: Sincronización encolada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EntityTenantSyncQueuedResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-entities-id-tenant-syncs
  /v1/portal_builder:
    get:
      tags:
        - Constructor del Portal
      summary: Consultar el constructor del portal
      description: "Devuelve el portal del workspace como lo ve el constructor: identidad del portal, borrador (páginas en el orden del menú, cada una con su marca respecto a la versión publicada, `revision` y `dirty`), número de la versión publicada, versiones publicadas, tema y SEO predeterminado. Lea la `revision` aquí antes de guardar el borrador."
      security:
        - bearerAuth: []
      responses:
        "200":
          description: El constructor del portal.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-builder
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/draft:
    put:
      tags:
        - Constructor del Portal
      summary: Guardar el borrador del portal
      description: "Sustituye el borrador completo — páginas en el orden del menú, estado del editor y, opcionalmente, tema y SEO predeterminado — protegido por la última `revision` leída. Una `revision` desactualizada responde 409 y no cambia nada. Nada se publica: para publicar, use `POST /portal_builder/publish`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderDraftRequest"
      responses:
        "200":
          description: "Borrador guardado: nueva `revision`, si difiere de la versión publicada y la marca de cada página."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderDraftSaveResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "La `revision` enviada está desactualizada: otra persona o pestaña guardó el borrador. Léalo de nuevo y reenvíe."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-portal-builder-draft
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/publish:
    post:
      tags:
        - Constructor del Portal
      summary: Publicar el portal
      description: "Guarda el borrador tal como se envía (mismo cuerpo que el guardado, más una `note` opcional) y lo congela como la próxima versión, en una sola transacción: los visitantes del portal la ven de inmediato. Un campo de formulario cuya expresión regular puede bloquear la validación responde 422 `UNSAFE_FIELD_PATTERN`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderPublishRequest"
      responses:
        "201":
          description: Versión publicada, con la nueva `revision` del borrador.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderPublishResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: "La `revision` enviada está desactualizada: otra persona o pestaña guardó el borrador. Léalo de nuevo y reenvíe."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Una expresión regular de campo de formulario puede bloquear la validación (`UNSAFE_FIELD_PATTERN`); `details` indica página, bloque y campo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-publish
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/versions/{number}:
    get:
      tags:
        - Constructor del Portal
      summary: Consultar una versión publicada
      description: Devuelve una versión publicada del portal, por número, con las páginas que congeló.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: Número de la versión publicada (`1`, `2`…).
            example: "3"
          required: true
          name: number
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La versión y sus páginas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalVersionDetailResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-builder-versions-number
  /v1/portal_builder/versions/{number}/rollback:
    post:
      tags:
        - Constructor del Portal
      summary: Restaurar una versión
      description: Vuelve a publicar esa versión como el próximo número — los visitantes del portal la ven de inmediato. Devuelve la nueva versión y el constructor tal como quedó.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: Número de la versión publicada (`1`, `2`…).
            example: "3"
          required: true
          name: number
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "201":
          description: Nueva versión publicada y el constructor actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderRollbackResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Esa versión ya está publicada (`ALREADY_LIVE`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-versions-number-rollback
  /v1/portal_builder/secrets:
    post:
      tags:
        - Constructor del Portal
      summary: Cifrar un secreto de bloque
      description: "Cifra un valor que un bloque guarda en el JSON de la página (una cabecera de webhook como `Authorization`). Devuelve `secret:<cifrado>`, vinculado a este workspace y al origen de `url` (obligatoria), que solo el servidor abre para enviar la solicitud a ese origen. Nada se almacena: guarde el valor devuelto en el bloque junto con el borrador."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderSecretRequest"
      responses:
        "200":
          description: El valor cifrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderSecretResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: La `url` no tiene un origen http(s) fijo — por ejemplo, una `{{variable}}` en el dominio (`ACTION_SECRET_URL_REQUIRED`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-secrets
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/og_image:
    post:
      tags:
        - Constructor del Portal
      summary: Subir una imagen og:image
      description: Sube la og:image de una página (o del SEO predeterminado) — la imagen que muestran las vistas previas de enlaces — y devuelve su URL pública, para guardar en `seo.og_image_url` (o `seo_defaults.og_image_url`) en el próximo guardado del borrador. PNG, JPEG o WebP, en base64; hasta 2 MB de imagen, pero el cuerpo completo de la solicitud tiene un límite de 2 MB (cerca de 1,5 MB de imagen ya codificada).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderOgImageRequest"
      responses:
        "201":
          description: Imagen subida, con su URL pública.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderOgImageResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "413":
          description: El cuerpo de la solicitud supera los 2 MB.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Tipo no aceptado, base64 inválido, imagen por encima del límite o contenido que no corresponde al `content_type`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-og-image
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/form_submissions:
    post:
      tags:
        - Constructor del Portal
      summary: Probar un formulario del borrador
      description: "Ejecuta la acción de un bloque Formulario como la vista previa del constructor: el correo configurado se envía de verdad (o el webhook elegido se dispara de verdad), marcado como `preview: true`. La configuración del formulario viene en el cuerpo. El correo de prueba va solo al correo del operador del token (un token sin operador no prueba la acción de correo). Limitado a 20 ejecuciones por minuto por operador, 60 por minuto y 500 por día por organización, compartiendo el límite con la vista previa del panel."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderFormSubmissionRequest"
      responses:
        "200":
          description: "Envío registrado: destinatarios, notificaciones o la entrega del webhook."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderFormSubmissionResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Valores que no cumplen las reglas del formulario, expresión regular peligrosa o acción mal configurada; `field_errors` lista los campos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-form-submissions
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_builder/action_runs:
    post:
      tags:
        - Constructor del Portal
      summary: Probar un botón de acción del borrador
      description: "Ejecuta el webhook de un Botón de acción como la vista previa del constructor: la solicitud sale de verdad, marcada como `preview: true`, y la respuesta trae el estado HTTP devuelto por el destino. Las cabeceras pueden llevar valores `secret:` creados por `POST /portal_builder/secrets`, que solo se abren para el origen para el que fueron creados. Limitado a 20 ejecuciones por minuto por operador, 60 por minuto y 500 por día por organización."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalBuilderActionRunRequest"
      responses:
        "200":
          description: Resultado de la ejecución.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalBuilderActionRunResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Solicitud mal configurada (URL sin https, cabecera inválida, secreto de otro workspace…).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-builder-action-runs
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_settings:
    get:
      tags:
        - Configuración del Portal
      summary: Obtener configuración del portal
      description: "Devuelve la configuración del portal del workspace: marca, idioma de la página, colores, dirección, opciones de inicio de sesión y SSO, notificaciones y remitente, y configuración del sitio (cabeceras de seguridad, SEO, rastreadores, chat y código propio)."
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Configuración del portal del workspace, con los valores predeterminados aplicados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSettingsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-settings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    patch:
      tags:
        - Configuración del Portal
      summary: Actualizar configuración del portal
      description: "Actualiza la configuración del portal del workspace. Parcial: solo cambian los campos enviados. Devuelve la configuración completa."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalSettingsUpdateRequest"
      responses:
        "200":
          description: Configuración del portal del workspace, con los valores predeterminados aplicados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSettingsResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Rechazado por una regla de negocio (dirección en uso o reservada, archivo demasiado grande o de tipo no aceptado…).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-portal-settings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_settings/logo:
    post:
      tags:
        - Configuración del Portal
      summary: Subir imagen del portal
      description: Sube el logo, el logo para fondos oscuros o el favicon del portal, en base64 en el cuerpo JSON. Reemplaza la imagen anterior.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalLogoUploadRequest"
      responses:
        "201":
          description: Imagen guardada; `url` es su dirección pública.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalLogoUploadResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Rechazado por una regla de negocio (dirección en uso o reservada, archivo demasiado grande o de tipo no aceptado…).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-settings-logo
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    delete:
      tags:
        - Configuración del Portal
      summary: Eliminar imagen del portal
      description: Elimina el logo, el logo para fondos oscuros o el favicon; el portal vuelve al predeterminado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            enum:
              - logo
              - logo_light
              - favicon
            description: "Qué imagen: `logo` (predeterminado), `logo_light` (logo para fondos oscuros) o `favicon`."
          required: false
          name: variant
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Imagen eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalLogoDeleteResponse"
        "400":
          description: Solicitud inválida (parámetro ausente o con formato incorrecto).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-portal-settings-logo
  /v1/portal_settings/domain:
    patch:
      tags:
        - Configuración del Portal
      summary: Definir dirección del portal
      description: Define la dirección del portal en la plataforma, `https://{slug}.{domain}`, o la elimina cuando ambos son `null`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalDomainUpdateRequest"
      responses:
        "200":
          description: Dirección actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalDomainResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Rechazado por una regla de negocio (dirección en uso o reservada, archivo demasiado grande o de tipo no aceptado…).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-portal-settings-domain
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_settings/domain/check_slug:
    get:
      tags:
        - Configuración del Portal
      summary: Verificar disponibilidad de la dirección
      description: Indica si `slug.domain` está libre para el portal de este workspace (su dirección actual cuenta como libre).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: "Subdominio: 3 a 50 letras minúsculas, números y guiones (sin guion en los extremos). `null` para eliminar."
            example: acme
          required: true
          name: slug
          in: query
        - schema:
            type: string
            description: Uno de los dominios de la plataforma (`available_domains`). `null` para eliminar.
          required: true
          name: domain
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Resultado de la verificación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSlugCheckResponse"
        "400":
          description: Solicitud inválida (parámetro ausente o con formato incorrecto).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-settings-domain-check-slug
  /v1/portal_settings/sender_identity:
    post:
      tags:
        - Configuración del Portal
      summary: Verificar remitente de las notificaciones
      description: Solicita o consulta la verificación del remitente en AWS SES. Si la dirección nunca se envió a SES o la verificación falló, SES le envía un enlace de confirmación; si no, consulta el estado actual.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Estado de la verificación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSenderIdentityResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-settings-sender-identity
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_custom_domains:
    get:
      tags:
        - Dominios Propios del Portal
      summary: Listar dominios propios
      description: Lista los dominios propios del portal del workspace (conjunto completo, sin paginación). Vacía donde los dominios propios no son compatibles.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Dominios propios del portal.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalCustomDomainListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-custom-domains
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Dominios Propios del Portal
      summary: Agregar dominio propio
      description: "Registra un dominio propio como `pending_verification`, sin tocar AWS, y devuelve los registros DNS a publicar. Luego llame a `POST /portal_custom_domains/{id}/verify`. El registro es solo un reclamo: el dominio queda con el primer portal que publique su TXT de verificación (los demás reclamos no comprobados se liberan), y un reclamo no comprobado vence a los 7 días. Cada portal tiene como máximo 10 dominios. Los dominios de la plataforma (`kobana.com.br`, `kobana.tech` y los dominios compartidos de portal) no se aceptan. 403 donde los dominios propios no están disponibles."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalCustomDomainCreateRequest"
      responses:
        "201":
          description: El dominio propio.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalCustomDomainResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: Este dominio ya está registrado (comprobado por otro portal, o ya reclamado por este).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Dominio reservado de la plataforma (`hostname_reserved`) o el portal alcanzó su límite de dominios (`domain_limit_reached`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-custom-domains
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_custom_domains/{id}:
    delete:
      tags:
        - Dominios Propios del Portal
      summary: Eliminar dominio propio
      description: Elimina el dominio propio y deshace su tenant de CloudFront y el certificado, cuando están aprovisionados. El portal deja de responder en esa dirección.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del dominio propio.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSettingsDeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-portal-custom-domains-id
  /v1/portal_custom_domains/{id}/verify:
    post:
      tags:
        - Dominios Propios del Portal
      summary: Verificar y aprovisionar dominio propio
      description: Mientras está pendiente, verifica el DNS y aprovisiona el dominio en AWS (certificado y tenant de CloudFront); una vez aprovisionado, actualiza su estado. Devuelve el dominio con su nuevo `status`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del dominio propio.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El dominio propio.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalCustomDomainResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-custom-domains-id-verify
  /v1/portal_custom_domains/{id}/dns_status:
    get:
      tags:
        - Dominios Propios del Portal
      summary: Consultar DNS del dominio propio
      description: Consulta de solo lectura de los CNAME requeridos, registro por registro, sin cambiar nada en AWS.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del dominio propio.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Estado del DNS.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalCustomDomainDnsStatusResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-custom-domains-id-dns-status
  /v1/portal_oauth_providers:
    get:
      tags:
        - Proveedores OIDC del Portal
      summary: Listar proveedores OIDC
      description: Lista los proveedores OpenID Connect con los que los usuarios entran al portal (conjunto completo, sin paginación).
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Proveedores OIDC del portal.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalOAuthProviderListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-oauth-providers
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Proveedores OIDC del Portal
      summary: Agregar proveedor OIDC
      description: Agrega un proveedor OpenID Connect al inicio de sesión del portal.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalOAuthProviderCreateRequest"
      responses:
        "201":
          description: El proveedor (sin el secret).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalOAuthProviderResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-oauth-providers
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_oauth_providers/{id}:
    patch:
      tags:
        - Proveedores OIDC del Portal
      summary: Actualizar proveedor OIDC
      description: "Actualiza un proveedor OpenID Connect. Parcial: solo cambian los campos enviados."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del proveedor OIDC.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalOAuthProviderUpdateRequest"
      responses:
        "200":
          description: El proveedor (sin el secret).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalOAuthProviderResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-portal-oauth-providers-id
    delete:
      tags:
        - Proveedores OIDC del Portal
      summary: Eliminar proveedor OIDC
      description: Elimina el proveedor; su botón desaparece del inicio de sesión y nadie más puede entrar por él.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del proveedor OIDC.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalSettingsDeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-portal-oauth-providers-id
  /v1/portal_oauth_providers/test:
    post:
      tags:
        - Proveedores OIDC del Portal
      summary: Probar emisor OIDC
      description: "Obtiene el documento de descubrimiento del emisor e informa sus endpoints, para validar la URL antes de guardar. Una falla en el descubrimiento es un 200 con `ok: false`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalOAuthProviderTestRequest"
      responses:
        "200":
          description: Resultado de la prueba.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalOAuthProviderTestResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-portal-oauth-providers-test
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/webhooks:
    get:
      tags:
        - Webhooks
      summary: Listar endpoints de webhook
      description: Lista los endpoints de webhook del workspace, del más reciente al más antiguo, con el total de entregas de cada uno.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - active
              - inactive
            description: "`active` o `inactive`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Fragmento de la URL o de la descripción, sin distinguir mayúsculas.
          required: false
          name: search
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de endpoints de webhook.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-webhooks
    post:
      tags:
        - Webhooks
      summary: Crear endpoint de webhook
      description: Crea un endpoint activo en el workspace. La respuesta trae el `secret` de firma — solo aparece aquí (y en la rotación).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookCreateRequest"
      responses:
        "201":
          description: Endpoint creado, con el secreto de firma.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookWithSecretResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-webhooks
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/webhooks/{id}:
    get:
      tags:
        - Webhooks
      summary: Consultar endpoint de webhook
      description: Devuelve un endpoint de webhook del workspace. Las entregas están en `GET /webhooks/{id}/deliveries`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El endpoint de webhook.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-webhooks-id
    patch:
      tags:
        - Webhooks
      summary: Actualizar endpoint de webhook
      description: Cambia la URL, la descripción, los eventos suscritos, `active` o la autenticación. Los campos ausentes quedan como están.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WebhookUpdateRequest"
      responses:
        "200":
          description: Endpoint actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-webhooks-id
    delete:
      tags:
        - Webhooks
      summary: Eliminar endpoint de webhook
      description: Elimina el endpoint definitivamente, junto con el log de entregas. Los eventos dejan de enviarse de inmediato.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Endpoint eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-webhooks-id
  /v1/webhooks/{id}/test:
    post:
      tags:
        - Webhooks
      summary: Enviar webhook de prueba
      description: "Envía ahora un evento `test.webhook` firmado a la URL del endpoint y lo registra en el log de entregas. Responde 200 con `success: false` cuando el endpoint responde fuera de 2xx o no se alcanza, y 422 cuando la URL apunta a una dirección bloqueada (red privada)."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Resultado del intento.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookTestResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-webhooks-id-test
  /v1/webhooks/{id}/rotate_secret:
    post:
      tags:
        - Webhooks
      summary: Rotar el secreto del webhook
      description: Genera un nuevo secreto de firma. El anterior deja de valer de inmediato; el nuevo `secret` solo aparece en esta respuesta.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Endpoint con el nuevo secreto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookWithSecretResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-webhooks-id-rotate-secret
  /v1/webhooks/{id}/deliveries:
    get:
      tags:
        - Webhooks
      summary: Listar entregas de un webhook
      description: Log de entregas de un endpoint, de la más reciente a la más antigua.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - pending
              - delivered
              - failed
            description: "`pending`, `delivered` o `failed`."
          required: false
          name: status
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de entregas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-webhooks-id-deliveries
  /v1/webhooks/{id}/deliveries/{delivery_id}/retry:
    post:
      tags:
        - Webhooks
      summary: Reintentar entrega de webhook
      description: "Devuelve la entrega a `pending` y la encola para un nuevo envío. El envío es asíncrono: siga el resultado en el log de entregas."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del endpoint de webhook.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entrega, obtenido en el log de entregas.
          required: true
          name: delivery_id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "202":
          description: Entrega encolada para reenvío.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryRetryResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-webhooks-id-deliveries-delivery-id-retry
  /v1/webhook_deliveries:
    get:
      tags:
        - Webhooks
      summary: Listar entregas de webhook
      description: Entregas de todos los endpoints del workspace, de la más reciente a la más antigua, con el tipo de evento y el resumen del endpoint.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - pending
              - delivered
              - failed
            description: "`pending`, `delivered` o `failed`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Solo entregas de este endpoint de webhook.
          required: false
          name: webhook_id
          in: query
        - schema:
            type: string
            description: Límite inferior de `created_at` (fecha o fecha-hora ISO 8601).
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            description: Límite superior de `created_at` (fecha o fecha-hora ISO 8601). Una fecha sin hora cubre el día entero (UTC).
          required: false
          name: date_to
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de entregas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryListResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-webhook-deliveries
  /v1/webhook_deliveries/{id}:
    get:
      tags:
        - Webhooks
      summary: Consultar entrega de webhook
      description: "Devuelve una entrega: la solicitud (redactada), la respuesta, los intentos y el endpoint de destino."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la entrega.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La entrega.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WebhookDeliveryResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-webhook-deliveries-id
  /v1/events:
    get:
      tags:
        - Eventos
      summary: Listar eventos
      description: "Log de eventos del workspace y de la organización, del más reciente al más antiguo. Los eventos son evidencia: no se pueden cambiar ni eliminar."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: "Tipo exacto del evento (ej.: `api_key.rotated`)."
          required: false
          name: type
          in: query
        - schema:
            type: string
            description: "Tipo exacto del recurso (ej.: `api_key`)."
          required: false
          name: resource_type
          in: query
        - schema:
            type: string
            format: uuid
            description: Solo eventos de este registro.
          required: false
          name: resource_id
          in: query
        - schema:
            type: string
            description: Límite inferior de `created_at` (fecha o fecha-hora ISO 8601).
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            description: Límite superior de `created_at` (fecha o fecha-hora ISO 8601). Una fecha sin hora cubre el día entero (UTC).
          required: false
          name: date_to
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de eventos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EventListResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-events
  /v1/events/{id}:
    get:
      tags:
        - Eventos
      summary: Consultar evento
      description: Devuelve un evento con el payload completo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del evento.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El evento.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EventResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-events-id
  /v1/audit_logs:
    get:
      tags:
        - Auditoría
      summary: Listar registros de auditoría
      description: Auditoría del workspace y de la organización, del más reciente al más antiguo. La auditoría no se puede cambiar.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Identificador exacto del usuario.
          required: false
          name: user_id
          in: query
        - schema:
            type: string
            description: "Acción exacta (ej.: `webhook.created`)."
          required: false
          name: action
          in: query
        - schema:
            type: string
            description: "Tipo exacto del recurso (ej.: `webhook`)."
          required: false
          name: resource_type
          in: query
        - schema:
            type: string
            description: ID exacto del recurso.
          required: false
          name: resource_id
          in: query
        - schema:
            type: string
            description: Fragmento de la acción, del tipo de recurso, del ID o del correo del usuario, sin distinguir mayúsculas.
          required: false
          name: search
          in: query
        - schema:
            type: string
            description: Límite inferior de `created_at` (fecha o fecha-hora ISO 8601).
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            description: Límite superior de `created_at` (fecha o fecha-hora ISO 8601). Una fecha sin hora cubre el día entero (UTC).
          required: false
          name: date_to
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de registros de auditoría.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditLogListResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-audit-logs
  /v1/audit_logs/summary:
    get:
      tags:
        - Auditoría
      summary: Resumen de la actividad auditada
      description: "Actividad de las últimas `hours` horas: total de registros, las 10 acciones más frecuentes y los 20 registros más recientes. Requiere el permiso de exportar auditoría."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: number
            minimum: 1
            maximum: 8760
            description: Tamaño de la ventana en horas, de 1 a 8760. Por defecto 24.
            example: 24
          required: false
          name: hours
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Resumen de la actividad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditLogSummaryResponse"
        "400":
          description: "Solicitud inválida: cuerpo malformado, campo obligatorio ausente o filtro con valor inválido."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-audit-logs-summary
  /v1/audit_logs/{id}:
    get:
      tags:
        - Auditoría
      summary: Consultar registro de auditoría
      description: Devuelve un registro de auditoría con los valores anteriores y nuevos.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del registro de auditoría.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El registro de auditoría.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AuditLogResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-audit-logs-id
  /v1/email_templates:
    get:
      tags:
        - Plantillas de Correo
      summary: Listar plantillas de correo
      description: Lista las plantillas de correo de la propia organización, ordenadas por tipo y nombre. Devuelve el conjunto completo, sin paginación.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            enum:
              - api_key_expiring
              - account_suspended
              - account_activated
              - portal_invitation
              - portal_signup_verification
              - magic_link_portal
              - magic_link_dashboard
              - email_verification
              - password_reset
              - welcome
              - email_change_verification
              - password_verification
              - account_invitation
              - organization_welcome
              - dashboard_user_welcome
            description: Solo plantillas de este tipo de notificación.
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: "`true` para las plantillas activas, `false` para los borradores."
          required: false
          name: is_active
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Plantillas de la organización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-email-templates
    post:
      tags:
        - Plantillas de Correo
      summary: Crear plantilla de correo
      description: Crea una plantilla para un tipo de notificación. Queda como borrador, salvo que `is_active` sea `true` — entonces la plantilla activa anterior del tipo pasa a borrador.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailTemplateCreateRequest"
      responses:
        "201":
          description: Plantilla creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-templates
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/email_templates/init_defaults:
    post:
      tags:
        - Plantillas de Correo
      summary: Restaurar plantillas predeterminadas
      description: Crea o restaura la plantilla de cada tipo de notificación con el contenido predeterminado y la activa. Sobrescribe el contenido de las plantillas existentes de la organización.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Una fila por tipo de notificación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateDefaultsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-templates-init-defaults
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/email_templates/{id}:
    get:
      tags:
        - Plantillas de Correo
      summary: Consultar plantilla de correo
      description: Devuelve una plantilla de la organización o una predeterminada de la plataforma.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La plantilla.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-email-templates-id
    patch:
      tags:
        - Plantillas de Correo
      summary: Actualizar plantilla de correo
      description: Actualiza una plantilla de la organización. Solo cambian los campos enviados. Las predeterminadas de la plataforma no se pueden modificar (404).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailTemplateUpdateRequest"
      responses:
        "200":
          description: Plantilla actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: El `public_id` enviado ya está en uso.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-email-templates-id
    delete:
      tags:
        - Plantillas de Correo
      summary: Eliminar plantilla de correo
      description: "Elimina definitivamente una plantilla inactiva de la organización. La plantilla activa de un tipo no se puede eliminar (422): active otra antes."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Plantilla eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-email-templates-id
  /v1/email_templates/{id}/duplicate:
    post:
      tags:
        - Plantillas de Correo
      summary: Duplicar plantilla de correo
      description: Copia una plantilla como borrador (inactiva).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailTemplateDuplicateRequest"
      responses:
        "201":
          description: La copia creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-templates-id-duplicate
  /v1/email_templates/{id}/preview:
    get:
      tags:
        - Plantillas de Correo
      summary: Previsualizar plantilla de correo
      description: Renderiza la plantilla con datos de ejemplo, dentro del diseño de la organización. No se envía nada.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El correo renderizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateRenderResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-email-templates-id-preview
    post:
      tags:
        - Plantillas de Correo
      summary: Renderizar plantilla con variables
      description: Renderiza la plantilla con las `variables` enviadas, sin diseño. No se envía nada.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la plantilla.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailTemplateRenderRequest"
      responses:
        "200":
          description: El correo renderizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailTemplateRenderResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-templates-id-preview
  /v1/email_layouts:
    get:
      tags:
        - Diseños de Correo
      summary: Listar diseños de correo
      description: Lista los diseños de correo de la organización, el predeterminado primero. Devuelve el conjunto completo, sin paginación.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Diseños de la organización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLayoutListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-email-layouts
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Diseños de Correo
      summary: Crear diseño de correo
      description: Crea un diseño. El HTML debe contener el marcador `{{content}}`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailLayoutCreateRequest"
      responses:
        "201":
          description: Diseño creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLayoutResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-layouts
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/email_layouts/init_defaults:
    post:
      tags:
        - Diseños de Correo
      summary: Crear diseño predeterminado
      description: "Garantiza que la organización tenga un diseño predeterminado: devuelve el actual o crea el incorporado. Nunca sobrescribe un diseño."
      security:
        - bearerAuth: []
      responses:
        "200":
          description: El diseño predeterminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLayoutResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-email-layouts-init-defaults
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/email_layouts/{id}:
    get:
      tags:
        - Diseños de Correo
      summary: Consultar diseño de correo
      description: Devuelve un diseño de la organización.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del diseño.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El diseño.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLayoutResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-email-layouts-id
    patch:
      tags:
        - Diseños de Correo
      summary: Actualizar diseño de correo
      description: Actualiza nombre, HTML (que debe mantener `{{content}}`), predeterminado o activo. Solo cambian los campos enviados.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del diseño.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/EmailLayoutUpdateRequest"
      responses:
        "200":
          description: Diseño actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/EmailLayoutResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-email-layouts-id
    delete:
      tags:
        - Diseños de Correo
      summary: Eliminar diseño de correo
      description: Elimina definitivamente un diseño. Los correos pasan a usar el diseño predeterminado (o el incorporado).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) del diseño.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Diseño eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-email-layouts-id
  /v1/notifications:
    get:
      tags:
        - Notificaciones
      summary: Listar notificaciones
      description: Lista las notificaciones del workspace y las de toda la organización, de las más nuevas a las más antiguas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - api_key_expiring
              - account_suspended
              - account_activated
              - portal_invitation
              - portal_signup_verification
              - magic_link_portal
              - magic_link_dashboard
              - email_verification
              - password_reset
              - welcome
              - email_change_verification
              - password_verification
              - account_invitation
              - organization_welcome
              - dashboard_user_welcome
            description: Solo este tipo de notificación.
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - email
              - in_app
              - webhook
            description: Solo este canal.
          required: false
          name: channel
          in: query
        - schema:
            type: string
            enum:
              - pending
              - sent
              - delivered
              - failed
              - read
              - skipped
            description: Solo este estado.
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            description: Fragmento del destinatario o del asunto, sin distinguir mayúsculas.
          required: false
          name: search
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de notificaciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NotificationListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-notifications
    post:
      tags:
        - Notificaciones
      summary: Crear notificación
      description: Renderiza la plantilla activa del tipo con las variables, guarda la notificación y la envía en el momento — la respuesta trae el resultado (`sent`, o `failed` con `failure_reason`). Con un `scheduled_for` en el futuro, queda `pending` hasta la hora marcada. Cada creación cuenta en el límite de envíos manuales por destinatario (429).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NotificationCreateRequest"
      responses:
        "201":
          description: Notificación creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NotificationResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-notifications
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/notifications/stats:
    get:
      tags:
        - Notificaciones
      summary: Estadísticas de notificaciones
      description: Conteos por estado, tipo y canal de las notificaciones creadas en los últimos `days` días, con las tasas de entrega y de lectura.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            maximum: 365
            description: Ventana en días, de 1 a 365. Por defecto 30.
            example: 30
          required: false
          name: days
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Las estadísticas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NotificationStatsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-notifications-stats
  /v1/notifications/{id}/send:
    post:
      tags:
        - Notificaciones
      summary: Enviar notificación
      description: "Envía ahora una notificación guardada: el primer envío de una `pending` (programada) o `skipped`, o el reenvío de una `sent`, `delivered`, `read` o `failed`. Cada llamada envía el correo de nuevo y cuenta en el límite de envíos manuales por destinatario (429)."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la notificación.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La notificación actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NotificationSendResponse"
        "400":
          description: Solicitud inválida (campo obligatorio ausente, tipo o variables inválidos).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "502":
          description: El proveedor de correo rechazó el envío; el motivo viene en el mensaje.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-notifications-id-send
  /v1/api_keys:
    get:
      tags:
        - Claves de API
      summary: Listar claves de API
      description: "Lista las claves de API (`kb_…`) de la organización, sin el secreto. Estas claves ya no autentican la API v1 ni el MCP — ambos usan tokens de acceso emitidos por el servidor de autorización de Kobana; los registros siguen como inventario de claves de la organización (ciclo de vida, avisos de vencimiento y webhooks `api_key.*`). Recurso de la organización: ignora `X-Workspace-Id`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - active
              - disabled
              - revoked
            description: "Filtra por estado: `active`, `disabled` o `revoked`."
          required: false
          name: status
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de claves de API.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-api-keys
    post:
      tags:
        - Claves de API
      summary: Crear clave de API
      description: Crea una clave activa, válida por un año salvo `expires_at`. El secreto (`key`) vuelve UNA sola vez en esta respuesta — solo se guarda su hash. Exige una persona que alcance todos los workspaces (dueña de la organización o con acceso a cada uno), como en el panel.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApiKeyCreateRequest"
      responses:
        "201":
          description: Clave creada, con el secreto en `key` (mostrado solo ahora).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyCreatedResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-api-keys
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/api_keys/{id}:
    get:
      tags:
        - Claves de API
      summary: Consultar clave de API
      description: Devuelve una clave de la organización — metadatos y marcas del ciclo de vida, nunca el secreto.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la clave de API.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La clave de API.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-api-keys-id
    patch:
      tags:
        - Claves de API
      summary: Actualizar clave de API
      description: Edita nombre, descripción, origen, correos de aviso y vencimiento, y/o activa ⇄ desactiva la clave con `enabled`. Una clave revocada es definitiva (409).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la clave de API.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApiKeyUpdateRequest"
      responses:
        "200":
          description: La clave de API.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: El estado actual del recurso no permite esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-api-keys-id
    delete:
      tags:
        - Claves de API
      summary: Eliminar clave revocada
      description: Quita de la lista una clave YA REVOCADA (borrado lógico; el historial se conserva). Una clave activa o desactivada debe revocarse antes (409).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la clave de API.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: El estado actual del recurso no permite esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-api-keys-id
  /v1/api_keys/{id}/revoke:
    post:
      tags:
        - Claves de API
      summary: Revocar clave de API
      description: Revoca la clave de forma definitiva — no puede reactivarse. 409 si ya está revocada.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la clave de API.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La clave de API.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: El estado actual del recurso no permite esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-api-keys-id-revoke
  /v1/api_keys/{id}/rotate:
    post:
      tags:
        - Claves de API
      summary: Rotar clave de API
      description: Emite una clave sucesora (mismo nombre y configuración) y mantiene la anterior funcionando durante `grace_days` días (por defecto 7, máximo 30). Solo una clave activa puede rotarse (409). El nuevo secreto vuelve UNA sola vez.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la clave de API.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ApiKeyRotateRequest"
      responses:
        "200":
          description: La clave sucesora con el secreto en `key`, y `previous_key` con el plazo de gracia de la anterior.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiKeyRotatedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "409":
          description: El estado actual del recurso no permite esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-api-keys-id-rotate
  /v1/exports:
    get:
      tags:
        - Exportaciones
      summary: Listar exportaciones
      description: Lista las solicitudes de exportación del workspace.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Recurso exportado, p. ej. `portal_users`.
          required: false
          name: resource_type
          in: query
        - schema:
            type: string
            enum:
              - pending
              - processing
              - completed
              - failed
            description: Filtra por estado de la exportación.
          required: false
          name: status
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de exportaciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExportListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-exports
    post:
      tags:
        - Exportaciones
      summary: Solicitar exportación
      description: "Programa la exportación de los usuarios del portal del workspace en CSV, XLSX o JSON. Asíncrono: responde 202 con la exportación `pending`; consulte `GET /exports/{id}` hasta `completed` y descargue en `/download`. El archivo vence en 7 días."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExportCreateRequest"
      responses:
        "202":
          description: Exportación programada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExportResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-exports
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/exports/{id}:
    get:
      tags:
        - Exportaciones
      summary: Consultar exportación
      description: Estado y metadatos de una solicitud de exportación.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la exportación.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La exportación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExportResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-exports-id
  /v1/exports/{id}/download:
    get:
      tags:
        - Exportaciones
      summary: Descargar archivo de la exportación
      description: Devuelve el archivo de una exportación terminada (el panel redirige a una URL firmada; la API entrega los bytes). 404 mientras no esté lista.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la exportación.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El archivo, como adjunto.
          content:
            text/csv:
              schema:
                type: string
                format: binary
            application/vnd.openxmlformats-officedocument.spreadsheetml.sheet:
              schema:
                type: string
                format: binary
            application/json:
              schema:
                type: string
                format: binary
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-exports-id-download
  /v1/imports:
    get:
      tags:
        - Importaciones
      summary: Listar importaciones
      description: Lista las solicitudes de importación del workspace, con contadores de éxito y error.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            description: Recurso importado, p. ej. `portal_users`.
          required: false
          name: resource_type
          in: query
        - schema:
            type: string
            enum:
              - pending
              - processing
              - completed
              - completed_with_errors
              - failed
            description: Filtra por estado de la importación.
          required: false
          name: status
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de importaciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-imports
    post:
      tags:
        - Importaciones
      summary: Importar CSV
      description: 'Envía un CSV en base64 y programa la importación de usuarios del portal en el workspace. El panel sube el archivo antes; la API lo recibe en el cuerpo (límite de 2 MB por solicitud). Sigue la configuración de la organización "permitir crear usuarios del portal" (403 si está desactivada). Asíncrono: 202; consulte `GET /imports/{id}`.'
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ImportCreateRequest"
      responses:
        "202":
          description: Importación programada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-imports
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/imports/{id}:
    get:
      tags:
        - Importaciones
      summary: Consultar importación
      description: Estado, contadores y errores por fila de una importación. Una importación aún `pending` 2 minutos después de la solicitud aparece como `failed` (cola detenida), sin que la consulta modifique el registro.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la importación.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La importación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ImportResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-imports-id
  /v1/backups:
    get:
      tags:
        - Copias de seguridad
      summary: Listar copias de seguridad
      description: Lista copias de seguridad y restauraciones de la organización (solo metadatos) e informa si puede pedirse una nueva copia ahora (`backup_allowed`, `next_backup_at` — una cada 12 horas en producción). Recurso de la organización.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - backup
              - restore
            description: "`backup` o `restore`."
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - pending
              - processing
              - completed
              - failed
              - canceled
            description: Filtra por estado.
          required: false
          name: status
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Página de copias de seguridad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackupListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-backups
    post:
      tags:
        - Copias de seguridad
      summary: Solicitar copia de seguridad
      description: "Programa una copia completa (ZIP) de la organización, con todos los workspaces. Asíncrono: 202; consulte `GET /backups/{id}`."
      security:
        - bearerAuth: []
      responses:
        "202":
          description: Copia programada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackupResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Aún dentro del intervalo de 12 horas entre copias (`BACKUP_COOLDOWN`, con `next_backup_at`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-backups
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/backups/restore:
    post:
      tags:
        - Copias de seguridad
      summary: Restaurar copia de seguridad
      description: "DESTRUCTIVO: restaura una copia en el workspace de la llamada (`X-Workspace-Id`), reescribiendo usuarios del portal emparejados por correo/ID público. Envíe `backup_id` (una copia terminada de esta organización — el archivo se copia) O `file_name` (`.zip`) + `content_base64` (limitado a los 2 MB de la solicitud). Exige `settings.update` y acceso a todos los workspaces. Asíncrono: 202; sígala en `GET /backups/{id}` y cancele con `/cancel`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BackupRestoreRequest"
      responses:
        "202":
          description: Restauración programada (registro de tipo `restore`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackupResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-backups-restore
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/backups/{id}:
    get:
      tags:
        - Copias de seguridad
      summary: Consultar copia de seguridad
      description: Estado y progreso de una copia o restauración. Una restauración en curso cuyo job desapareció de la cola se marca como `failed`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la copia o restauración.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La copia de seguridad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackupResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-backups-id
    delete:
      tags:
        - Copias de seguridad
      summary: Eliminar copia de seguridad
      description: Elimina el registro y su archivo del almacenamiento. Definitivo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la copia o restauración.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-backups-id
  /v1/backups/{id}/cancel:
    post:
      tags:
        - Copias de seguridad
      summary: Cancelar restauración
      description: Detiene una restauración pendiente o en curso. Lo ya restaurado permanece. 422 para una copia o una restauración ya terminada.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la copia o restauración.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: La copia de seguridad.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BackupResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-backups-id-cancel
  /v1/backups/{id}/download:
    get:
      tags:
        - Copias de seguridad
      summary: Descargar copia de seguridad
      description: Devuelve el ZIP de la copia. Exige `backups.export` y, para el token de una persona, ser dueña de la organización o tener acceso a todos los workspaces — la copia los contiene a todos. Queda en la auditoría.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID (UUID) de la copia o restauración.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El archivo ZIP.
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-backups-id-download
  /v1/data_purges:
    get:
      tags:
        - Limpieza de Datos
      summary: Contar datos eliminables
      description: Cuántos registros tiene cada recurso eliminable (`portal_users`, `people`, `usage_history`) sumando todos los workspaces. Exige `data.purge` (por defecto solo dueños de la organización) y acceso a todos los workspaces.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Los conteos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPurgeCountsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-purges
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    post:
      tags:
        - Limpieza de Datos
      summary: Eliminar datos de la organización
      description: "IRREVERSIBLE: elimina definitivamente los recursos elegidos en TODOS los workspaces de la organización. En el panel la operación se confirma con un código enviado por correo. Por eso, un token que identifica a una persona (token personal, OAuth o llamada por el MCP) recibe 403: la persona hace la limpieza desde el panel. Solo los tokens de máquina pueden limpiar por la API, y solo cuando el token trae el scope dedicado `dashboards/data_purges:write` — concedido explícitamente: ningún otro scope lo implica (ni `write`, `all`, `dashboards/all` o `dashboards/admin:write`); sin él, 403 `insufficient_scope`. Su confirmación es `confirm`, que debe repetir el ID de la organización (de `GET /organization`) — una llamada repetida o dirigida a la organización equivocada no pasa por error. Exige `data.purge` (por defecto solo dueños de la organización) y acceso a todos los workspaces. Asíncrono: 202 con `job_id`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataPurgeRequest"
      responses:
        "202":
          description: Limpieza programada; sígala en `GET /data_purges/{id}`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPurgeQueuedResponse"
        "400":
          description: Cuerpo ausente, JSON inválido o campos incompatibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: "`confirm` no coincide con el ID de la organización — no se eliminó nada."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-data-purges
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/data_purges/{id}:
    get:
      tags:
        - Limpieza de Datos
      summary: Seguir limpieza
      description: "Progreso y resultado de un job de limpieza. Job de otra organización: 404."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: El `job_id` devuelto por `POST /data_purges`.
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El job.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPurgeJobResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-data-purges-id
  /v1/maintenance/uppercase_names:
    post:
      tags:
        - Mantenimiento
      summary: Poner nombres en mayúsculas
      description: Convierte a mayúsculas el nombre de todo contacto vinculado a un usuario del portal del workspace. No es reversible (la grafía anterior no se guarda).
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Cuántos nombres cambiaron.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/MaintenanceUppercaseNamesResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-maintenance-uppercase-names
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/settings:
    get:
      tags:
        - Configuración
      summary: Consultar configuración de la organización
      description: Nombre, correo de soporte, zona horaria y las opciones de registros de la organización. Recurso de la organización.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: La configuración.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationSettingsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-settings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    put:
      tags:
        - Configuración
      summary: Actualizar configuración de la organización
      description: "Cambia parcialmente la configuración: envíe solo lo que cambia. Los campos desconocidos se rechazan (400)."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/OrganizationSettingsUpdateRequest"
      responses:
        "200":
          description: La configuración.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationSettingsResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-settings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/usage:
    get:
      tags:
        - Consumo
      summary: Consultar consumo de la plataforma
      description: "Para cada métrica (miembros, clientes, usuarios del portal, integraciones…), la serie diaria en el período, el valor más reciente y el pico. Por defecto: mes actual; como máximo 12 meses atrás. Recurso de la organización."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: date
            description: "Primer día (AAAA-MM-DD). Por defecto: día 1 del mes actual."
            example: 2026-01-15
          required: false
          name: start_date
          in: query
        - schema:
            type: string
            format: date
            description: "Último día (AAAA-MM-DD). Por defecto: hoy."
            example: 2026-01-15
          required: false
          name: end_date
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El consumo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SystemUsageResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-usage
  /v1/ai_usage:
    get:
      tags:
        - Uso de IA
      summary: Consultar uso de IA
      description: "Consumo de IA, solo precio (costo y margen nunca salen): totales, detalle diario y últimos turnos del workspace de la llamada, más el acumulado del mes, franquicias, límites, saldo de crédito y si el próximo turno está permitido — estos de toda la organización, pues el límite y el crédito son compartidos. Período por defecto: mes actual (America/Sao_Paulo), como máximo 366 días."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: date
            description: Primer día (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: start_date
          in: query
        - schema:
            type: string
            format: date
            description: Último día (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: end_date
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 366
            description: Los últimos N días, en lugar de un rango de fechas.
          required: false
          name: days
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El uso de IA.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AiUsageResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-ai-usage
  /v1/rate_limits:
    get:
      tags:
        - Límites de Solicitudes
      summary: Consultar límites de solicitudes
      description: Los límites de solicitudes vigentes para la organización, si son personalizados (definidos por el equipo Kobana) y los valores por defecto de la plataforma. Solo lectura.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Los límites.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RateLimitsResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-rate-limits
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/portal_user_mappings:
    get:
      tags:
        - Usuarios del Portal
      summary: Consultar mapeo de usuarios del portal
      description: La entidad que alimenta a los usuarios del portal del workspace (`mapping`, `null` si no hay, con el resultado de la última sincronización) y las entidades que pueden mapearse, con sus campos.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: El mapeo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserMappingGetResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-portal-user-mappings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    put:
      tags:
        - Usuarios del Portal
      summary: Mapear entidad a usuarios del portal
      description: "Mapea una entidad: un usuario del portal por correo de sus registros, con el ID del titular tomado de un campo. Reemplaza el mapeo anterior y sincroniza en el acto (devuelve `stats`); las próximas sincronizaciones de la entidad mantienen a los usuarios al día."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PortalUserMappingUpdateRequest"
      responses:
        "200":
          description: El mapeo guardado y el resultado de la sincronización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserMappingUpdateResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: Entidad o campo inválido (p. ej., entidad que sincroniza al acceder).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: put-portal-user-mappings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
    delete:
      tags:
        - Usuarios del Portal
      summary: Eliminar mapeo de usuarios del portal
      description: Deja de sincronizar; los usuarios ya creados permanecen.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: "Mapeo eliminado (`deleted: false` si no había)."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PortalUserMappingDeleteResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-portal-user-mappings
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/assets:
    get:
      tags:
        - Archivos
      summary: Listar archivos
      description: La biblioteca de archivos del workspace — imágenes y documentos que el portal muestra u ofrece para descargar. Ordenable por `created_at` (por defecto), `name` o `size_bytes`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Página (comienza en 1). Por defecto: `1`."
            example: 1
          required: false
          name: page
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            description: "Ítems por página. Por defecto: `20`. Máximo: `100`."
            example: 20
          required: false
          name: per_page
          in: query
        - schema:
            type: string
            description: Campo de ordenación. El valor por defecto depende del recurso.
          required: false
          name: sort_by
          in: query
        - schema:
            type: string
            enum:
              - asc
              - desc
            description: "Dirección de ordenación. Por defecto: `desc`."
          required: false
          name: sort_order
          in: query
        - schema:
            type: string
            enum:
              - image
              - document
              - other
            description: "Filtra por tipo: `image`, `document` u `other`."
          required: false
          name: kind
          in: query
        - schema:
            type: string
            enum:
              - public
              - restricted
              - private
            description: "Quién puede descargarlo: `public` (cualquiera con el enlace), `restricted` (usuarios con sesión en el portal del workspace) o `private` (solo miembros del panel). Los archivos nuevos empiezan `restricted`."
          required: false
          name: visibility
          in: query
        - schema:
            type: string
            description: Parte del nombre del archivo (sin distinguir mayúsculas).
          required: false
          name: search
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Lista paginada de archivos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetListResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-assets
    post:
      tags:
        - Archivos
      summary: Agregar archivo
      description: "Registra un archivo en la biblioteca, de una de dos formas: el `key` de un archivo ya enviado por la URL de `POST /assets/presign`, o el propio contenido en `content_base64`. El archivo empieza `restricted`, salvo que `visibility` diga otra cosa. Dispara el webhook `asset.created`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssetCreateRequest"
      responses:
        "201":
          description: Archivo registrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-assets
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/assets/presign:
    post:
      tags:
        - Archivos
      summary: Generar URL de envío
      description: Una URL firmada y de corta duración para enviar el archivo directo al storage con `PUT` — el camino para archivos que superan el límite de 2 MB del cuerpo. Después del `PUT`, registre el archivo en `POST /assets` con el `key` devuelto.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssetPresignRequest"
      responses:
        "200":
          description: URL de envío generada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetPresignResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: post-assets-presign
      parameters:
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
  /v1/assets/{id}:
    get:
      tags:
        - Archivos
      summary: Consultar archivo
      description: Un archivo de la biblioteca, con su enlace, visibilidad, tipo y tamaño.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del archivo (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El archivo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-assets-id
    patch:
      tags:
        - Archivos
      summary: Actualizar archivo
      description: Renombra el archivo, cambia el texto alternativo o la visibilidad. Hacerlo público abre la URL del storage a cualquiera; `restricted` o `private` la cierra.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del archivo (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AssetUpdateRequest"
      responses:
        "200":
          description: Archivo actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssetResponse"
        "400":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "422":
          description: El cuerpo de la solicitud falló en la validación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: patch-assets-id
    delete:
      tags:
        - Archivos
      summary: Eliminar archivo
      description: Quita el archivo de la biblioteca. El archivo guardado sigue en el storage, para que los enlaces ya publicados no se rompan. Dispara el webhook `asset.deleted`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del archivo (UUID).
          required: true
          name: id
          in: path
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: Archivo eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeletedResponse"
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: delete-assets-id
  /v1/assets/{id}/download:
    get:
      tags:
        - Archivos
      summary: Descargar archivo
      description: El contenido del archivo, sea cual sea la visibilidad, con su propio `Content-Type`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del archivo (UUID).
          required: true
          name: id
          in: path
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: "Con `true`, imágenes y PDF vienen para mostrarse en el lugar (`Content-Disposition: inline`); los demás tipos vienen siempre como adjunto."
          required: false
          name: inline
          in: query
        - name: User-Agent
          in: header
          required: true
          description: "Identificación del integrador. Incluya nombre y correo de contacto — ej.: `Kevin Mitnick <kmitnick@kobana.com.br>`. Usado para soporte y auditoría."
          schema:
            type: string
            example: Kevin Mitnick <kmitnick@kobana.com.br>
          example: Kevin Mitnick <kmitnick@kobana.com.br>
        - name: X-Idempotency-Key
          in: header
          required: false
          description: Clave única (se recomienda UUID v4) para reintentar la misma solicitud sin efectos secundarios. Solicitudes con la misma clave en 24h devuelven el resultado original.
          schema:
            type: string
            format: uuid
        - name: X-Request-Source
          in: header
          required: false
          description: "Superficie que hace la llamada: `dashboard`, `api`, `cli`, `mcp` u `other`. Se guarda en `created_via` / `updated_via` de los registros creados o modificados. Sin la cabecera, se asume `api`. Un valor desconocido devuelve 400."
          schema:
            type: string
            enum:
              - dashboard
              - api
              - cli
              - mcp
              - other
            default: api
        - name: X-Workspace-Id
          in: header
          required: false
          description: "Workspace en el que actúa la llamada: el `id` o el `public_id` que se muestran en Workspaces en el panel. Dentro de la organización del token, los datos viven en workspaces. Puede omitirse mientras la organización tenga un único workspace; con dos o más, omitirlo devuelve `400 workspace_required`. Un workspace que no es de la organización devuelve `403 unknown_workspace`. Con un token de persona, solo los workspaces a los que ella tiene acceso (los propietarios de la organización alcanzan todos); los demás devuelven `403 workspace_access_denied`."
          schema:
            type: string
            format: uuid
        - name: X-Request-Source-Other
          in: header
          required: false
          description: Nombre de la aplicación que hace la llamada. Obligatorio cuando `X-Request-Source` es `other` (hasta 100 caracteres); se ignora en los demás casos. Se guarda en `created_via_other` / `updated_via_other`.
          schema:
            type: string
            maxLength: 100
            example: Zapier
      responses:
        "200":
          description: El contenido del archivo.
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        "401":
          description: Token bearer ausente o inválido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "403":
          description: Token válido, pero sin permiso para esta operación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "404":
          description: Recurso no encontrado en la organización actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "429":
          description: Límite de solicitudes excedido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
        "500":
          description: Error inesperado en el servidor.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiV1Error"
      operationId: get-assets-id-download
webhooks: {}
