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

    > **Índice de la documentación** — accede al índice completo en [https://docs.billing.kobana.com.br/llms.txt](https://docs.billing.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 Facturación Automática, que cubre los endpoints de **Suscripciones** (creación, cambio de plan, pausa, cancelación, facturación manual, sincronización de ítems) y recursos relacionados. 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` |
    | **Money** | Número decimal en BRL, con hasta 4 decimales. Ej.: `100.5` = R$ 100,50 |
    | **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).

    ## Valores monetarios

    Todo valor monetario — en la petición y en la respuesta — es un número decimal en BRL, con hasta 4 decimales. No hay campos en centavos: envía `100.5` para R$ 100,50 y `0.0125` para R$ 0,0125. Los campos de precios admiten los 4 decimales; los demás se redondean a 2.
  license:
    name: Proprietário — Kobana
    url: https://kobana.com.br
servers:
  - url: https://api.billing.kobana.com.br
    description: Producción. Sustituido en tiempo de ejecución cuando `API_V1_PUBLIC_URL` está definido.
  - url: https://api.billing.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
    SubscriptionV1:
      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 en su sistema externo, para idempotencia/sincronización.
        billing_account_id:
          type: string
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
        plan_id:
          type:
            - string
            - "null"
          format: uuid
        product_group_id:
          type:
            - string
            - "null"
          format: uuid
        status:
          type: string
          enum:
            - draft
            - confirmed
            - trialing
            - active
            - past_due
            - canceled
            - paused
            - suspended
          description: "Estado de la suscripción. Ciclo: `draft` → `confirmed` → `trialing` → `active` ↔ `past_due` → `canceled`. También acepta `paused`."
        billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
          description: "Periodicidad de cobro: mensual, trimestral, semestral o anual."
        current_period_start:
          type: string
          format: date-time
          description: Inicio del período de cobro actual.
        current_period_end:
          type: string
          format: date-time
          description: Fin del período de cobro actual.
        cycle_billing_date:
          type: string
          format: date-time
          description: "Fecha de facturación del ciclo: cuándo se genera la próxima factura de la suscripción. Su día del mes también define las facturas mensuales de excedente."
        trial_start:
          type:
            - string
            - "null"
          format: date-time
        trial_end:
          type:
            - string
            - "null"
          format: date-time
        activated_at:
          type:
            - string
            - "null"
          format: date-time
        confirmed_at:
          type:
            - string
            - "null"
          format: date-time
        cancel_at_period_end:
          type: boolean
          description: Cuando es `true`, la suscripción se cancela al fin del período actual en vez de inmediatamente.
        canceled_at:
          type:
            - string
            - "null"
          format: date-time
        cancellation_reason:
          type:
            - string
            - "null"
        pause_collection:
          description: Cuando está pausada, contiene `{ behavior, resumes_at }`. `null` cuando está activa.
        paused_at:
          type:
            - string
            - "null"
          format: date-time
        resumes_at:
          type:
            - string
            - "null"
          format: date-time
        resumed_at:
          type:
            - string
            - "null"
          format: date-time
        discount_percent:
          type:
            - string
            - "null"
          description: 'Decimal como string (ej.: `"10.00"` = 10%). Rango: 0–100.'
        discount_amount:
          type:
            - number
            - "null"
          description: "Descuento fijo por factura (ciclo de facturación) en BRL (float, hasta 4 decimales). Soberano sobre `discount_percent`: al definir el porcentaje este valor se recalcula; al definir este valor el porcentaje se borra."
          example: 50
        recurring_amount:
          type:
            - number
            - "null"
          description: Importe recurrente en BRL (float, hasta 4 decimales).
          example: 99.9
        proration_behavior:
          type: string
          enum:
            - create_prorations
            - none
            - always_invoice
          description: "Comportamiento de prorrata al cambiar de plan. `create_prorations` (por defecto): genera ajuste; `none`: ignora; `always_invoice`: emite factura inmediata."
        late_fee_policy_id:
          type:
            - string
            - "null"
          format: uuid
          description: Política de intereses y multas aplicada a las facturas de esta suscripción. Nulo hereda de la cuenta de cobro y, luego, del valor por defecto de la organización.
        collection_method:
          type:
            - string
            - "null"
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
          description: "`charge_automatically`: facturación y cobro automáticos. `manual_charge`: facturación automática, cobro manual. `manual_invoice`: ambos manuales."
        nfe_issuance_policy:
          type:
            - string
            - "null"
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
          description: "Política de emisión de NF-e: `disabled`, `on_finalization`, `on_full_payment` o `per_installment`."
        renewal_settings:
          description: '`{ type: "auto_renew" | "cancel" | "downgrade_to_flexible", ... }`.'
        commitment: {}
        commitment_months:
          type:
            - integer
            - "null"
          description: "Permanencia: número de meses contratados (copiado de la propuesta aceptada). Dentro de la ventana de permanencia — inicio de la suscripción + meses — el cliente no puede cancelar por el portal. Use `null` para quitar."
        allow_pause:
          type: boolean
        allow_cancel:
          type: boolean
        proposal_id:
          type:
            - string
            - "null"
          format: uuid
        notes:
          type:
            - string
            - "null"
        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
      required:
        - id
        - public_id
        - external_id
        - billing_account_id
        - company_id
        - plan_id
        - product_group_id
        - status
        - billing_cycle
        - current_period_start
        - current_period_end
        - cycle_billing_date
        - trial_start
        - trial_end
        - activated_at
        - confirmed_at
        - cancel_at_period_end
        - canceled_at
        - cancellation_reason
        - discount_percent
        - discount_amount
        - recurring_amount
        - proration_behavior
        - late_fee_policy_id
        - collection_method
        - nfe_issuance_policy
        - commitment_months
        - allow_pause
        - allow_cancel
        - proposal_id
        - notes
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    SubscriptionListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/SubscriptionV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    SubscriptionResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/SubscriptionV1"
      required:
        - data
    SubscriptionCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro que recibirá esta suscripción.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
        plan_id:
          type: string
          format: uuid
          description: UUID del plan. Obligatorio cuando no se envía `items`.
        product_group_id:
          type: string
          format: uuid
        billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        collection_method:
          type:
            - string
            - "null"
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
        trial_end:
          type: string
          format: date-time
          description: Fecha de finalización del trial (ISO 8601).
        trial_period_days:
          type: integer
          minimum: 0
          description: Alternativa a `trial_end`. Días de trial a partir de la creación.
        proration_behavior:
          type: string
          enum:
            - create_prorations
            - none
            - always_invoice
        nfe_issuance_policy:
          type: string
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
        items:
          type: array
          items:
            type: object
            properties:
              product_id:
                type: string
                format: uuid
              price_id:
                type: string
                format: uuid
              quantity:
                type: integer
                minimum: 1
                default: 1
              unit_amount:
                type: number
                minimum: 0
                description: Precisión de 4 decimales (float, hasta 4 decimales). Sobrescribe el importe del precio.
            required:
              - product_id
              - price_id
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: "Permanencia: número de meses contratados (copiado de la propuesta aceptada). Dentro de la ventana de permanencia — inicio de la suscripción + meses — el cliente no puede cancelar por el portal. Use `null` para quitar."
        notes:
          type:
            - string
            - "null"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
      required:
        - billing_account_id
    SubscriptionUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador en su sistema externo. Usa `null` para limpiar.
        plan_id:
          type:
            - string
            - "null"
          format: uuid
        billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        collection_method:
          type:
            - string
            - "null"
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
        cancel_at_period_end:
          type: boolean
        discount_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
        discount_amount:
          type:
            - number
            - "null"
          minimum: 0
          description: "Descuento fijo por factura (ciclo de facturación) en BRL (float, hasta 4 decimales). Soberano sobre `discount_percent`: al definir el porcentaje este valor se recalcula; al definir este valor el porcentaje se borra."
        proration_behavior:
          type: string
          enum:
            - create_prorations
            - none
            - always_invoice
        nfe_issuance_policy:
          type:
            - string
            - "null"
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
        allow_pause:
          type: boolean
        allow_cancel:
          type: boolean
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: "Permanencia: número de meses contratados (copiado de la propuesta aceptada). Dentro de la ventana de permanencia — inicio de la suscripción + meses — el cliente no puede cancelar por el portal. Use `null` para quitar."
        notes:
          type:
            - string
            - "null"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    SubscriptionPauseRequest:
      type: object
      properties:
        behavior:
          type: string
          enum:
            - mark_uncollectible
            - keep_as_draft
            - void
          description: "Cómo tratar facturas generadas durante la pausa. Por defecto: `mark_uncollectible`."
        resumes_at:
          type: string
          format: date-time
          description: Fecha para reanudación automática. Omita para reanudación manual.
    SubscriptionChangePlanRequest:
      type: object
      properties:
        plan_id:
          type: string
          format: uuid
          description: UUID del nuevo plan.
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo entra en vigor el cambio de plan. Por defecto: `immediate`."
        reason:
          type: string
          description: Motivo del cambio (opcional, registrado en el audit log).
      required:
        - plan_id
    SubscriptionChangeAnniversaryRequest:
      type: object
      properties:
        anniversary_day:
          type: integer
          minimum: 1
          maximum: 28
          description: Nuevo día del mes (1 a 28) en que empiezan los ciclos. Use 1 para mes calendario.
          example: 1
        charge_proration:
          type: boolean
          description: "Cobrar los días añadidos. Por defecto: `true`, salvo cuando el `proration_behavior` de la suscripción es `none`."
        dry_run:
          type: boolean
          description: Cuando es `true`, solo calcula y devuelve el resultado, sin cambiar nada.
        reason:
          type: string
          description: Motivo del cambio (opcional, registrado en el audit log).
      required:
        - anniversary_day
    SubscriptionChangeAnniversaryResult:
      type: object
      properties:
        dry_run:
          type: boolean
          description: Si fue solo una simulación.
        anniversary_day:
          type: integer
          description: Nuevo día de inicio de los ciclos.
        previous_next_cycle_start:
          type: string
          format: date-time
          description: Inicio del próximo ciclo antes del cambio.
        next_cycle_start:
          type: string
          format: date-time
          description: Inicio del próximo ciclo después del cambio.
        current_period_end:
          type: string
          format: date-time
          description: Nuevo fin (inclusivo) del ciclo en curso.
        proration_period_start:
          type: string
          format: date-time
          description: Primer día añadido al ciclo en curso.
        proration_period_end:
          type: string
          format: date-time
          description: Último día añadido al ciclo en curso.
        proration_days:
          type: integer
          description: Cantidad de días añadidos.
        cycle_days:
          type: integer
          description: Días del ciclo usados como divisor de la prorrata.
        cycle_amount:
          type: number
          description: Importe contratado de un ciclo completo, ya con descuento.
          example: 310
        proration_amount:
          type: number
          description: Importe proporcional de los días añadidos.
          example: 280
        charge_proration:
          type: boolean
          description: Si se cobran los días añadidos.
        will_invoice:
          type: boolean
          description: Si se genera (o generaría) una factura. Falso para cortesía, importe cero o `charge_proration=false`.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: Factura de la prorrata, cuando se genera.
        pending_usage:
          type:
            - object
            - "null"
          properties:
            period_start:
              type: string
              format: date-time
              description: Inicio del mes de excedente.
            period_end:
              type: string
              format: date-time
              description: Fin del mes de excedente.
            amount:
              type: number
              description: Importe de la factura de excedente.
              example: 45.5
          required:
            - period_start
            - period_end
            - amount
          description: Excedente del mes anterior que el nuevo día dejaría sin cobrar (el día antiguo aún no llegó y el nuevo ya pasó este mes). Se factura en el momento del cambio, como lo haría la facturación automática. Solo se rellena en la simulación (`dry_run`); en el cambio efectivo, vea `usage_invoice_id`. `null` cuando no hay riesgo o no hay consumo.
        usage_invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: Factura de excedente generada por el cambio, si la hubo.
      required:
        - dry_run
        - anniversary_day
        - previous_next_cycle_start
        - next_cycle_start
        - current_period_end
        - proration_period_start
        - proration_period_end
        - proration_days
        - cycle_days
        - cycle_amount
        - proration_amount
        - charge_proration
        - will_invoice
        - invoice_id
        - pending_usage
        - usage_invoice_id
    SubscriptionCancelRequest:
      type: object
      properties:
        cancel_at_period_end:
          type: boolean
          description: "Cuando es `true`, programa la cancelación para el fin del período actual. Por defecto: `false` (cancela inmediatamente)."
        reason:
          type: string
    BillingAccountCustomerV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        external_id:
          type:
            - string
            - "null"
        name:
          type: string
        nickname:
          type:
            - string
            - "null"
        legal_name:
          type:
            - string
            - "null"
        document_type:
          type:
            - string
            - "null"
          enum:
            - cpf
            - cnpj
        document_number:
          type:
            - string
            - "null"
        kind:
          type:
            - string
            - "null"
          enum:
            - individual
            - company
        birthday:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
        addresses: {}
        phones: {}
        emails: {}
        websites: {}
        tags:
          type:
            - array
            - "null"
          items:
            type: string
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - name
    BillingAccountV1:
      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 cuenta en el sistema del cliente.
        currency:
          type: string
          description: "Moneda ISO 4217 (ej.: `BRL`)."
          example: BRL
        billing_email:
          type:
            - string
            - "null"
          format: email
          description: Correo al que se envían facturas y avisos.
        late_fee_policy_id:
          type:
            - string
            - "null"
          format: uuid
          description: Política de intereses y multas negociada para este cliente. Nulo hereda el valor por defecto de la organización — nunca significa "sin cargo", que es una política explícita.
        payment_terms_days:
          type: integer
          description: "Plazo de vencimiento de factura en días (por defecto: 10)."
          example: 10
        auto_collection:
          type: boolean
          description: Cuando es `true`, los cobros se realizan automáticamente.
        balance:
          type: number
          description: Saldo de la cuenta en BRL (float, hasta 4 decimales).
          example: 0
        status:
          type: string
          enum:
            - active
            - suspended
            - closed
          description: "Estado de la cuenta: `active`, `suspended` o `closed`."
        suspended_at:
          type:
            - string
            - "null"
          format: date-time
        suspension_reason:
          type:
            - string
            - "null"
        tax_exempt:
          type: boolean
          description: Indica si la cuenta está exenta de impuestos.
        tax_exemption_certificate:
          type:
            - string
            - "null"
          description: Número del certificado de exención tributaria.
        customer_tax_type:
          type:
            - string
            - "null"
          enum:
            - individual
            - business
            - exempt
          description: "Tipo tributario del cliente: persona física, jurídica o exento."
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        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
        customer:
          allOf:
            - $ref: "#/components/schemas/BillingAccountCustomerV1"
            - description: Cliente asociado, presente cuando la relación está cargada.
      required:
        - id
        - public_id
        - external_id
        - currency
        - billing_email
        - late_fee_policy_id
        - payment_terms_days
        - auto_collection
        - balance
        - status
        - suspended_at
        - suspension_reason
        - tax_exempt
        - tax_exemption_certificate
        - customer_tax_type
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    BillingAccountListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BillingAccountV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    BillingAccountResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/BillingAccountV1"
      required:
        - data
    BillingAccountCustomerInput:
      type: object
      properties:
        id:
          type: string
          description: UUID o external_id del cliente existente.
        external_id:
          type: string
          description: External code para localizar/crear el cliente.
        document_number:
          type: string
          description: CPF o CNPJ para localizar/crear el cliente.
        name:
          type: string
          description: Obligatorio al crear un nuevo cliente.
        nickname:
          type: string
        legal_name:
          type: string
        kind:
          type: string
          enum:
            - individual
            - company
        birthday:
          type: string
        email:
          type: string
          format: email
        phone:
          type: string
        notes:
          type: string
        addresses: {}
        phones: {}
        emails: {}
        websites: {}
        tags:
          type: array
          items:
            type: string
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
    BillingAccountCreateRequest:
      type: object
      properties:
        customer:
          allOf:
            - $ref: "#/components/schemas/BillingAccountCustomerInput"
            - description: Cliente a asociar — existente o nuevo.
        external_id:
          type: string
          description: Identificador externo de la cuenta en el sistema del cliente.
        billing_email:
          type: string
          format: email
          description: "Correo de cobro. Por defecto: `customer.email`."
        payment_terms_days:
          type: integer
          minimum: 1
          maximum: 90
          description: "Plazo de vencimiento de factura en días (1–90). Por defecto: el plazo predeterminado configurado en la organización (10 cuando no está configurado)."
        auto_collection:
          type: boolean
          description: "Habilita el cobro automático. Por defecto: `true`."
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
      required:
        - customer
    BillingAccountUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador externo de la cuenta en el sistema del cliente. Envía `null` para limpiar.
        name:
          type: string
          minLength: 1
          maxLength: 255
        email:
          type: string
          format: email
        phone:
          type: string
        address:
          type: object
          additionalProperties: {}
        billing_email:
          type: string
          format: email
        payment_terms_days:
          type: integer
          minimum: 1
          maximum: 90
        auto_collection:
          type: boolean
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    BillingAccountReasonRequest:
      type: object
      properties:
        reason:
          type: string
          description: Motivo de la operación (registrado en el audit log).
    CustomerV1:
      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 del cliente en su sistema de origen.
        name:
          type: string
        nickname:
          type:
            - string
            - "null"
        legal_name:
          type:
            - string
            - "null"
          description: Razón social (para persona jurídica).
        document_type:
          type:
            - string
            - "null"
          enum:
            - cpf
            - cnpj
          description: Tipo del documento principal. Inferido por la longitud de `document_number`.
        document_number:
          type:
            - string
            - "null"
          description: CPF (11 dígitos) o CNPJ (14 dígitos). Puede contener máscara.
        kind:
          type:
            - string
            - "null"
          enum:
            - natural
            - juridical
          description: "`natural` para persona física; `juridical` para persona jurídica."
        birthday:
          type:
            - string
            - "null"
          description: Fecha de nacimiento (ISO 8601).
        notes:
          type:
            - string
            - "null"
        addresses:
          type:
            - array
            - "null"
          items:
            type: object
            properties:
              kind:
                type: string
                description: "Tipo de la dirección (ej.: `billing`, `shipping`)."
              street:
                type: string
              number:
                type: string
              complement:
                type:
                  - string
                  - "null"
              neighborhood:
                type: string
              city:
                type: string
              state:
                type: string
              postal_code:
                type: string
              country:
                type: string
                description: "Código ISO del país (ej.: `BR`)."
        phones:
          type:
            - array
            - "null"
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        emails:
          type:
            - array
            - "null"
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        websites:
          type:
            - array
            - "null"
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        tags:
          type:
            - array
            - "null"
          items:
            type: string
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados definidos por la organización.
        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
        billing_accounts:
          type: array
          items:
            $ref: "#/components/schemas/BillingAccountV1"
          description: Incluido solo cuando el cliente se carga con cuentas de cobro.
      required:
        - id
        - public_id
        - external_id
        - name
        - nickname
        - legal_name
        - document_type
        - document_number
        - kind
        - birthday
        - notes
        - addresses
        - phones
        - emails
        - websites
        - tags
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    CustomerListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CustomerV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CustomerResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CustomerV1"
      required:
        - data
    CustomerCreateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            customer:
              $ref: "#/components/schemas/CustomerV1"
            billing_account:
              allOf:
                - $ref: "#/components/schemas/BillingAccountV1"
                - type:
                    - object
                    - "null"
          required:
            - customer
            - billing_account
      required:
        - data
    CustomerCreateRequest:
      type: object
      properties:
        name:
          type: string
          description: Nombre del cliente (obligatorio).
        public_id:
          type: string
          format: uuid
          description: UUID público del cliente. Se genera cuando se omite; envíelo solo para conservar un identificador de su sistema. Debe ser único.
        external_id:
          type: string
          description: Identificador externo del cliente en el sistema de origen.
        nickname:
          type: string
        legal_name:
          type: string
          description: Razón social (para persona jurídica).
        document_number:
          type: string
          description: CPF o CNPJ. El `document_type` se infiere por la longitud (≤11 → cpf, si no cnpj).
        kind:
          type: string
          enum:
            - natural
            - juridical
        birthday:
          type: string
          description: Fecha de nacimiento (ISO 8601).
        email:
          type: string
          description: Correo principal de contacto.
        phone:
          type: string
        notes:
          type: string
        addresses:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
                description: "Tipo de la dirección (ej.: `billing`, `shipping`)."
              street:
                type: string
              number:
                type: string
              complement:
                type:
                  - string
                  - "null"
              neighborhood:
                type: string
              city:
                type: string
              state:
                type: string
              postal_code:
                type: string
              country:
                type: string
                description: "Código ISO del país (ej.: `BR`)."
        phones:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        emails:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        websites:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        tags:
          type: array
          items:
            type: string
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        create_billing_account:
          type: boolean
          description: "Cuando es `false`, no crea cuenta de cobro automáticamente. Por defecto: `true`."
        billing_email:
          type: string
          description: "Correo para envío de facturas. Por defecto: usa `email` cuando se omite."
        payment_terms_days:
          type: integer
          minimum: 0
          description: "Plazo de vencimiento de factura en días. Por defecto: el plazo predeterminado configurado en la organización (10 cuando no está configurado)."
        auto_collection:
          type: boolean
          description: "Cobro automático en la cuenta creada. Por defecto: `true`."
      required:
        - name
    CustomerUpdateRequest:
      type: object
      properties:
        name:
          type: string
        public_id:
          type: string
          format: uuid
          description: Nuevo UUID público del cliente. Debe ser único.
        external_id:
          type: string
        nickname:
          type: string
        legal_name:
          type: string
        document_number:
          type: string
        kind:
          type: string
          enum:
            - natural
            - juridical
        birthday:
          type: string
        email:
          type: string
        phone:
          type: string
        notes:
          type: string
        addresses:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
                description: "Tipo de la dirección (ej.: `billing`, `shipping`)."
              street:
                type: string
              number:
                type: string
              complement:
                type:
                  - string
                  - "null"
              neighborhood:
                type: string
              city:
                type: string
              state:
                type: string
              postal_code:
                type: string
              country:
                type: string
                description: "Código ISO del país (ej.: `BR`)."
        phones:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        emails:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        websites:
          type: array
          items:
            type: object
            properties:
              kind:
                type: string
              value:
                type: string
            required:
              - value
        tags:
          type: array
          items:
            type: string
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    CustomerUpsertRequest:
      allOf:
        - $ref: "#/components/schemas/CustomerCreateRequest"
        - type: object
          properties:
            name:
              type: string
              description: Nombre del cliente. Obligatorio solo cuando ningún cliente es encontrado por las claves de deduplicación.
            public_id:
              type: string
              format: uuid
              description: UUID público del cliente. Localiza el registro y, cuando no se encuentra ninguno, se guarda en el cliente creado.
            id:
              type: string
              format: uuid
              description: UUID del cliente. Se usa solo para localizar el registro — nunca se guarda.
            custom_metadata_mode:
              type: string
              enum:
                - replace
                - merge
              description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
              example: merge
    CustomerUpsertResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            customer:
              $ref: "#/components/schemas/CustomerV1"
            billing_account:
              allOf:
                - $ref: "#/components/schemas/BillingAccountV1"
                - type:
                    - object
                    - "null"
            matched_by:
              type:
                - string
                - "null"
              enum:
                - id
                - public_id
                - external_id
                - document_number
              description: Clave que localizó al cliente existente. `null` cuando el cliente fue creado.
          required:
            - customer
            - billing_account
            - matched_by
      required:
        - data
    CustomerStatementItem:
      type: object
      properties:
        id:
          type: string
          format: uuid
        billing_account_id:
          type: string
          format: uuid
        kind:
          type: string
          description: "Tipo del movimiento (ej.: `invoice`, `payment`, `credit_application`)."
        occurred_at:
          type: string
          format: date-time
        description:
          type:
            - string
            - "null"
        amount:
          type: number
          description: Importe del movimiento en BRL (float, hasta 4 decimales). Puede ser negativo.
        parent_id:
          type:
            - string
            - "null"
        parent_type:
          type:
            - string
            - "null"
        created_at:
          type: string
          format: date-time
      required:
        - id
        - billing_account_id
        - kind
        - occurred_at
        - description
        - amount
        - parent_id
        - parent_type
        - created_at
    CustomerStatementListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CustomerStatementItem"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CustomerStatementSyncResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            customer_id:
              type: string
              format: uuid
            billing_account_id:
              type: string
              format: uuid
            invoices_created:
              type: integer
            payments_created:
              type: integer
            credit_applications_created:
              type: integer
            total_created:
              type: integer
          required:
            - customer_id
            - billing_account_id
            - invoices_created
            - payments_created
            - credit_applications_created
            - total_created
      required:
        - data
    CustomerStatementSyncRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: Necesario cuando el cliente tiene múltiples cuentas de cobro.
    CustomerRecalculateMrrResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            customer_id:
              type: string
              format: uuid
            total_mrr:
              type: number
              description: MRR consolidado de todas las cuentas, en BRL (float, hasta 4 decimales).
            billing_accounts:
              type: array
              items:
                type: object
                properties:
                  billing_account_id:
                    type: string
                    format: uuid
                  mrr_amount:
                    type: number
                required:
                  - billing_account_id
                  - mrr_amount
          required:
            - customer_id
            - total_mrr
            - billing_accounts
      required:
        - data
    CustomerPortalUserV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público estable del recurso.
        email:
          type: string
        status:
          type: string
          enum:
            - active
            - pending_verification
            - pending_invitation
            - suspended
            - locked
        sso_only:
          type: boolean
        external_id:
          type:
            - string
            - "null"
        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 `Person` vinculado, cuando está cargado.
      required:
        - id
        - public_id
        - email
        - status
        - sso_only
        - external_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
    CustomerPortalUserListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CustomerPortalUserV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CustomerPortalUserResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CustomerPortalUserV1"
      required:
        - data
    CustomerPortalUserInviteRequest:
      type: object
      properties:
        email:
          type: string
          description: Correo del invitado (obligatorio).
        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:
        - email
    CustomerPortalUserUpdateRequest:
      type: object
      properties:
        email:
          type: string
        external_id:
          type:
            - string
            - "null"
        sso_only:
          type: boolean
        status:
          type: string
          enum:
            - active
            - suspended
          description: "Transiciones permitidas: `active` ↔ `suspended`."
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    CustomerPortalUserEmailPreviewResponse:
      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
    CustomerPortalUserResendResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            resent:
              type: boolean
            type:
              type: string
              enum:
                - invitation
                - verification
          required:
            - resent
            - type
      required:
        - data
    PlanItemV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        plan_id:
          type: string
          format: uuid
        product_id:
          type: string
          format: uuid
        price_id:
          type: string
          format: uuid
        quantity:
          type: integer
          description: Cantidad del producto incluida en el plan.
          example: 1
        included:
          type: boolean
          description: Cuando es `true`, el ítem está incluido en el precio del plan. Cuando es `false`, es un add-on cobrado por separado.
        created_at:
          type: string
          format: date-time
      required:
        - id
        - plan_id
        - product_id
        - price_id
        - quantity
        - included
        - created_at
    PlanV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type:
            - string
            - "null"
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
        plan_group_id:
          type:
            - string
            - "null"
          format: uuid
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: Cuando está definido, el plan es específico de una cuenta de cobro (plan custom).
        name:
          type: string
        slug:
          type: string
          description: Identificador único por organización. Solo `[a-z0-9-]`.
        description:
          type:
            - string
            - "null"
        status:
          type: string
          enum:
            - draft
            - active
            - archived
          description: "Estado del plan: `draft`, `active` o `archived`."
        plan_type:
          type: string
          enum:
            - standard
            - custom
            - promotional
          description: "`standard`: plan público estándar. `custom`: plan específico de cliente. `promotional`: plan promocional temporal."
        visibility:
          type: string
          enum:
            - public
            - private
          description: "`public`: visible en el catálogo. `private`: oculto."
        features:
          type: array
          items:
            type: string
          description: Lista de features del plan (strings libres).
        limits:
          type: object
          properties:
            users:
              type: integer
            subaccounts:
              type: integer
            operations_per_month:
              type: integer
            api_requests_per_day:
              type: integer
          description: Límites del plan (usuarios, subcuentas, operaciones, etc.).
        trial_period_days:
          type:
            - integer
            - "null"
          description: Días de trial concedidos al crear una suscripción de este plan.
        default_billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
          description: Periodicidad de cobro por defecto.
        available_billing_cycles:
          type: array
          items:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
          description: Periodicidades de cobro permitidas para este plan.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
        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
        items:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemV1"
          description: Ítems del plan. Presente cuando se incluye vía relations.
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - company_id
        - plan_group_id
        - billing_account_id
        - name
        - slug
        - description
        - status
        - plan_type
        - visibility
        - features
        - limits
        - trial_period_days
        - default_billing_cycle
        - available_billing_cycles
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    PlanListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PlanV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PlanResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanV1"
      required:
        - data
    PlanItemListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemV1"
      required:
        - data
    PlanItemInput:
      type: object
      properties:
        product_id:
          type: string
          format: uuid
        price_id:
          type: string
          format: uuid
        quantity:
          type: integer
          minimum: 1
          default: 1
        included:
          type: boolean
          default: true
      required:
        - product_id
        - price_id
    PlanCreateRequest:
      type: object
      properties:
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
        plan_group_id:
          type:
            - string
            - "null"
          format: uuid
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9-]+$
          description: Solo letras minúsculas, dígitos y guiones.
        description:
          type:
            - string
            - "null"
        status:
          type: string
          enum:
            - draft
            - active
            - archived
        plan_type:
          type: string
          enum:
            - standard
            - custom
            - promotional
          description: "Por defecto: `standard`."
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Por defecto: `public`."
        features:
          type: array
          items:
            type: string
        limits:
          type: object
          properties:
            users:
              type: integer
            subaccounts:
              type: integer
            operations_per_month:
              type: integer
            api_requests_per_day:
              type: integer
        trial_period_days:
          type: integer
          minimum: 0
          maximum: 90
        default_billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        available_billing_cycles:
          type: array
          items:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
        items:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemInput"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
      required:
        - name
        - slug
    PlanUpdateRequest:
      type: object
      properties:
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type:
            - string
            - "null"
          format: uuid
        plan_group_id:
          type:
            - string
            - "null"
          format: uuid
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9-]+$
          description: Solo letras minúsculas, dígitos y guiones.
        description:
          type:
            - string
            - "null"
        status:
          type: string
          enum:
            - draft
            - active
            - archived
        plan_type:
          type: string
          enum:
            - standard
            - custom
            - promotional
          description: "Por defecto: `standard`."
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Por defecto: `public`."
        features:
          type: array
          items:
            type: string
        limits:
          type: object
          properties:
            users:
              type: integer
            subaccounts:
              type: integer
            operations_per_month:
              type: integer
            api_requests_per_day:
              type: integer
        trial_period_days:
          type: integer
          minimum: 0
          maximum: 90
        default_billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        available_billing_cycles:
          type: array
          items:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
        items:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemInput"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
    PlanItemsReplaceRequest:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemInput"
      required:
        - items
    PlanItemsReplaceResponse:
      type: array
      items:
        $ref: "#/components/schemas/PlanItemV1"
    PlanBulkIdsRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs de planes. Mínimo 1.
      required:
        - ids
    PlanBulkMoveGroupRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
        plan_group_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del grupo destino. Usa `null` para quitar la agrupación.
      required:
        - ids
        - plan_group_id
    PlanBulkArchiveResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            archived_count:
              type: integer
            skipped_count:
              type: integer
            skipped_ids:
              type: array
              items:
                type: string
                format: uuid
          required:
            - archived_count
            - skipped_count
            - skipped_ids
      required:
        - data
    PlanBulkDeleteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted_count:
              type: integer
            skipped_count:
              type: integer
            skipped_ids:
              type: array
              items:
                type: string
                format: uuid
          required:
            - deleted_count
            - skipped_count
            - skipped_ids
      required:
        - data
    PlanBulkMoveGroupResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            moved_count:
              type: integer
          required:
            - moved_count
      required:
        - data
    PlanGroupV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type: string
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
        name:
          type: string
          description: Nombre del grupo de planes.
        slug:
          type:
            - string
            - "null"
          description: Identificador legible usado en URLs públicas.
        display_order:
          type: integer
          description: Posición de visualización (el valor menor aparece primero).
        archived_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha de archivado. `null` cuando está activo.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        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
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - company_id
        - name
        - slug
        - display_order
        - archived_at
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    PlanGroupListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PlanGroupV1"
      required:
        - data
    PlanGroupResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanGroupV1"
      required:
        - data
    PlanGroupCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del grupo de planes.
        slug:
          type: string
          minLength: 1
          maxLength: 100
          description: Identificador legible (opcional). Generado automáticamente si se omite.
        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
    PlanGroupUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 100
        external_id:
          type: string
          description: Nuevo identificador en su sistema externo.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    PlanGroupReorderRequest:
      type: object
      properties:
        group_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs de los grupos en el nuevo orden de visualización. Todos deben pertenecer a la organización actual.
      required:
        - group_ids
    PlanGroupReorderResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            success:
              type: boolean
              example: true
          required:
            - success
      required:
        - data
    ProductV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type:
            - string
            - "null"
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
        parent_product_id:
          type:
            - string
            - "null"
          format: uuid
        product_group_id:
          type:
            - string
            - "null"
          format: uuid
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
        name:
          type: string
          description: Nombre de visualización del producto.
        slug:
          type: string
          description: Identificador legible único dentro del grupo de productos. Acepta solo `[a-z0-9_-]+`.
        description:
          type:
            - string
            - "null"
        status:
          type: string
          enum:
            - draft
            - active
            - archived
          description: "Estado del producto: `draft`, `active` o `archived`."
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal del cliente. `public`: visible para clientes; `private`: solo operadores."
        product_type:
          type: string
          enum:
            - base
            - addon_quantity
            - addon_fixed
            - metered
            - one_time_fixed
            - one_time_quantity
            - credits
          description: "Tipo del producto. `base`: plan principal; `addon_quantity`/`addon_fixed`: complementos; `metered`: cobro por uso; `one_time_fixed`/`one_time_quantity`: cobro único; `credits`: créditos prepagos, comprados por separado."
        unit_label:
          type:
            - string
            - "null"
          description: 'Etiqueta de la unidad (ej.: "usuario", "GB"). Usada en facturas y portal.'
        increment:
          type: integer
          description: Incremento mínimo de cantidad al cambiar el ítem.
        website_url:
          type:
            - string
            - "null"
        display_order:
          type: integer
          description: Orden de visualización (menor primero).
        is_required:
          type: boolean
          description: Cuando es `true`, el producto es obligatorio en el plan en el que se incluye.
        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
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - company_id
        - parent_product_id
        - product_group_id
        - service_item_id
        - name
        - slug
        - description
        - status
        - visibility
        - product_type
        - unit_label
        - increment
        - website_url
        - display_order
        - is_required
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    ProductListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProductV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ProductResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProductV1"
      required:
        - data
    ProductCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del producto.
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9_-]+$
          description: Slug único dentro del grupo. Acepta solo `[a-z0-9_-]+`.
        description:
          type: string
        product_type:
          type: string
          enum:
            - base
            - addon_quantity
            - addon_fixed
            - metered
            - one_time_fixed
            - one_time_quantity
            - credits
          description: "Tipo del producto. Por defecto: `base`."
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal. Por defecto: `public`."
        unit_label:
          type: string
        increment:
          type: integer
          exclusiveMinimum: 0
          description: "Incremento mínimo. Por defecto: `1`."
        website_url:
          type: string
          format: uri
        is_required:
          type: boolean
        parent_product_id:
          type: string
          format: uuid
        product_group_id:
          type: string
          format: uuid
        company_id:
          type: string
          format: uuid
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
      required:
        - name
        - slug
    ProductUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9_-]+$
        description:
          type: string
        status:
          type: string
          enum:
            - draft
            - active
            - archived
        product_type:
          type: string
          enum:
            - base
            - addon_quantity
            - addon_fixed
            - metered
            - one_time_fixed
            - one_time_quantity
            - credits
        visibility:
          type: string
          enum:
            - public
            - private
        unit_label:
          type: string
        increment:
          type: integer
          exclusiveMinimum: 0
        website_url:
          type: string
          format: uri
        is_required:
          type: boolean
        parent_product_id:
          type:
            - string
            - "null"
          format: uuid
        product_group_id:
          type:
            - string
            - "null"
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
        external_id:
          type: string
          description: Nuevo identificador en su sistema externo.
        custom_metadata:
          type: object
          additionalProperties: {}
    ProductReorderRequest:
      type: object
      properties:
        product_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: IDs de productos en el nuevo orden deseado. El índice 0 pasa a ser el primero de la lista.
      required:
        - product_ids
    ProductBulkArchiveRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: IDs de productos a archivar.
      required:
        - ids
    ProductBulkDeleteRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: IDs de productos a eliminar permanentemente.
      required:
        - ids
    ProductBulkVisibilityRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
        visibility:
          type: string
          enum:
            - public
            - private
          description: Nueva visibilidad a aplicar en todos los productos.
      required:
        - ids
        - visibility
    ProductBulkMoveGroupRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
        product_group_id:
          type:
            - string
            - "null"
          format: uuid
          description: Grupo de destino. Usa `null` para quitar del grupo actual.
      required:
        - ids
        - product_group_id
    ProductBulkChangeCompanyRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa de destino. Usa `null` para limpiar el vínculo.
      required:
        - ids
        - company_id
    ProductBulkResultResponse:
      type: object
      properties:
        data: {}
    ProductGroupV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type: string
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora asociada al grupo (opcional).
        proposal_template_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la plantilla de propuesta por defecto del grupo (opcional).
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del ítem de servicio fiscal por defecto del grupo (opcional).
        name:
          type: string
          description: Nombre del grupo de productos.
        slug:
          type: string
          description: Identificador legible usado en URLs públicas. Único por organización.
        display_order:
          type: integer
          description: Orden de visualización del grupo (menor primero).
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal del cliente. `public`: visible para clientes; `private`: solo operadores."
        archived_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha de archivado. `null` cuando está activo.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        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
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - company_id
        - proposal_template_id
        - service_item_id
        - name
        - slug
        - display_order
        - visibility
        - archived_at
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    ProductGroupListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProductGroupV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ProductGroupResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProductGroupV1"
      required:
        - data
    ProductGroupCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del grupo.
        slug:
          type: string
          description: Slug del grupo. Generado a partir del nombre cuando se omite.
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal del cliente. Por defecto: `public`."
        company_id:
          type:
            - string
            - "null"
          format: uuid
        proposal_template_id:
          type:
            - string
            - "null"
          format: uuid
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
        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
    ProductGroupUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
        visibility:
          type: string
          enum:
            - public
            - private
          description: Nueva visibilidad en el portal del cliente (`public` o `private`).
        company_id:
          type:
            - string
            - "null"
          format: uuid
        proposal_template_id:
          type:
            - string
            - "null"
          format: uuid
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
        external_id:
          type: string
          description: Nuevo identificador en su sistema externo.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
    ProductGroupReorderRequest:
      type: object
      properties:
        group_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs en el nuevo orden deseado. Todos los IDs deben pertenecer a la organización.
      required:
        - group_ids
    ProductGroupReorderResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            success:
              type: boolean
              example: true
          required:
            - success
      required:
        - data
    ProductGroupDeletedResponse:
      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).
    CompanyPersonV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        nickname:
          type:
            - string
            - "null"
        legal_name:
          type:
            - string
            - "null"
          description: Razón social.
        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 (CPF o CNPJ), almacenado solo con dígitos.
        kind:
          type:
            - string
            - "null"
        birthday:
          type:
            - string
            - "null"
        notes:
          type:
            - string
            - "null"
        addresses: {}
        phones: {}
        emails: {}
        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"
        external_id:
          type:
            - string
            - "null"
          description: Identificador del registro `Person` en el sistema de origen.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - name
    CompanyV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type:
            - string
            - "null"
          description: Identificador público corto de la empresa (estable y seguro para mostrar).
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización (tenant) propietaria de la empresa.
        person_id:
          type: string
          format: uuid
          description: UUID del registro `Person` (identidad jurídica) asociado a la empresa.
        parent_company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la matriz cuando la empresa es una sucursal; `null` para matrices.
        is_default:
          type: boolean
          description: Indica si es la empresa predeterminada de la organización. Solo las matrices pueden ser predeterminadas.
        status:
          type: string
          enum:
            - active
            - inactive
          description: "Estado de la empresa: `active` o `inactive`."
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de la empresa (clave/valor libre).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados definidos por el cliente (clave/valor libre).
        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
        person:
          allOf:
            - $ref: "#/components/schemas/CompanyPersonV1"
            - description: Identidad jurídica de la empresa (nombre, razón social, documento, contactos).
      required:
        - id
        - public_id
        - organization_id
        - person_id
        - parent_company_id
        - is_default
        - status
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    CompanyListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CompanyV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CompanyResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CompanyV1"
      required:
        - data
    CompanyMatrizListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CompanyV1"
      required:
        - data
    CompanyDeleteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    CompanyCreateRequest:
      type: object
      properties:
        parent_company_id:
          type: string
          format: uuid
          description: UUID de la matriz al crear una sucursal. Omite para crear una matriz.
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre comercial de la empresa.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        legal_name:
          type: string
          maxLength: 255
          description: Razón social.
        document_type:
          type: string
          enum:
            - cpf
            - cnpj
          description: "Tipo de documento: `cpf` o `cnpj`. Solo `cnpj` puede tener sucursales."
        document_number:
          type: string
          minLength: 11
          maxLength: 18
          description: CPF o CNPJ (con o sin máscara — se normalizará a solo dígitos).
        email:
          type: string
          format: email
          description: Correo principal de la empresa.
        phone:
          type: string
          description: Teléfono principal de la empresa. Cuando se informa, se añade al array `phones`.
        addresses:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de direcciones de la empresa.
        emails:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de correos adicionales. Si se omite, se usa el `email` principal.
        phones:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de teléfonos de la empresa.
        websites:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de sitios web de la empresa.
        is_default:
          type: boolean
          description: Cuando es `true`, marca esta empresa como predeterminada de la organización. Solo las matrices pueden ser predeterminadas.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados (clave/valor libre).
      required:
        - name
        - document_type
        - document_number
        - email
    CompanyUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nuevo nombre comercial.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        legal_name:
          type: string
          maxLength: 255
          description: Nueva razón social.
        email:
          type: string
          format: email
          description: Nuevo correo principal. Actualiza la primera entrada del array `emails`.
        phone:
          type: string
          description: Nuevo teléfono principal. Actualiza la primera entrada del array `phones`.
        addresses:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Sustituye la lista de direcciones.
        emails:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Sustituye la lista de correos.
        phones:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Sustituye la lista de teléfonos.
        websites:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Sustituye la lista de sitios web.
        is_default:
          type: boolean
          description: Cuando es `true`, marca esta empresa como predeterminada. Usa el endpoint `set-default` para la operación dedicada.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Sustituye los metadatos personalizados.
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    CompanyFiscalProfileUpsertRequest:
      type: object
      properties:
        taxation_regime:
          type: string
          enum:
            - simple_national
            - presumed_profit
            - real_profit
            - mei
          description: "Régimen tributario: `simple_national`, `presumed_profit`, `real_profit` o `mei`."
        simples_annex:
          type:
            - string
            - "null"
          enum:
            - annex_iii
            - annex_iv
            - annex_v
          description: "Anexo del Simples Nacional: `annex_iii`, `annex_iv` o `annex_v`."
        rbt12:
          type:
            - number
            - "null"
          minimum: 0
          description: Ingreso bruto acumulado en los últimos 12 meses, en BRL (float, hasta 4 decimales).
        factor_r:
          type:
            - number
            - "null"
          description: Factor R (nómina ÷ ingreso), usado en la clasificación del Simples Nacional.
        cpp_inside_das:
          type: boolean
          description: Indica si la CPP (contribución previsional patronal) está incluida en el DAS.
        presumption_rate:
          type:
            - number
            - "null"
          description: "Alícuota de presunción (lucro presunto), en decimal (ej.: 0.32)."
        iss_municipality:
          type:
            - string
            - "null"
          description: Municipio donde se aplica el ISS.
        iss_rate:
          type:
            - number
            - "null"
          description: Alícuota del ISS, en decimal.
        pis_rate:
          type:
            - number
            - "null"
          description: Alícuota del PIS, en decimal.
        cofins_rate:
          type:
            - number
            - "null"
          description: Alícuota de COFINS, en decimal.
        csll_rate:
          type:
            - number
            - "null"
          description: Alícuota de CSLL, en decimal.
        irpj_rate:
          type:
            - number
            - "null"
          description: Alícuota de IRPJ, en decimal.
        cbs_ibs_enabled:
          type: boolean
          description: Habilita los campos CBS/IBS (Reforma Tributaria brasileña).
        cbs_rate:
          type:
            - number
            - "null"
          description: Alícuota de la CBS, en decimal.
        ibs_rate:
          type:
            - number
            - "null"
          description: Alícuota del IBS, en decimal.
        cbs_ibs_mode:
          type: string
          enum:
            - informative
            - compositive
          description: "Modo de cálculo CBS/IBS: `informative` (solo demostrativo) o `compositive` (compone el precio)."
      required:
        - taxation_regime
    CompanyFiscalProfileResponse:
      type: object
      properties:
        data: {}
    CertificatePersonV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del person.
        name:
          type: string
          description: Nombre del person.
        document_number:
          type:
            - string
            - "null"
          description: CPF o CNPJ del person.
      required:
        - id
        - name
        - document_number
    CertificateV1:
      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 en su sistema externo, para idempotencia/sincronización.
        person_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del `person` asociado (cuando el documento coincide con un registro existente).
        name:
          type: string
          description: Nombre amigable del certificado.
        status:
          type: string
          enum:
            - active
            - expired
            - revoked
          description: "Estado del certificado: `active`, `expired` o `revoked`."
        format:
          type: string
          enum:
            - pfx
            - pem
          description: "Formato del certificado almacenado: `pfx` o `pem`."
        document:
          type:
            - string
            - "null"
          description: CPF o CNPJ extraído del certificado (solo dígitos).
        common_name:
          type:
            - string
            - "null"
          description: Nombre común (`CN`) del subject del certificado.
        organization_name:
          type:
            - string
            - "null"
          description: Nombre de la organización (`O`) del subject.
        organizational_unit:
          type:
            - string
            - "null"
          description: Unidad organizativa (`OU`) del subject.
        issuer_common_name:
          type:
            - string
            - "null"
          description: Nombre común (`CN`) del emisor (AC).
        issuer_organization:
          type:
            - string
            - "null"
          description: Organización (`O`) del emisor (AC).
        serial_number:
          type:
            - string
            - "null"
          description: Número de serie del certificado.
        thumbprint:
          type:
            - string
            - "null"
          description: Thumbprint SHA-1 del certificado (hex en mayúsculas). Único por certificado.
        not_before:
          type:
            - string
            - "null"
          format: date-time
          description: Inicio de la validez del certificado (UTC).
        not_after:
          type:
            - string
            - "null"
          format: date-time
          description: Fin de la validez del certificado (UTC).
        metadata:
          type: object
          additionalProperties: {}
          description: Metadatos internos del certificado.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios 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
        person:
          allOf:
            - $ref: "#/components/schemas/CertificatePersonV1"
            - type:
                - object
                - "null"
              description: Resumen del `person` asociado (id, name, document_number), cuando se carga.
      required:
        - id
        - public_id
        - person_id
        - name
        - status
        - format
        - document
        - common_name
        - organization_name
        - organizational_unit
        - issuer_common_name
        - issuer_organization
        - serial_number
        - thumbprint
        - not_before
        - not_after
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    CertificateListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CertificateV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CertificateResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CertificateV1"
      required:
        - data
    CertificateUploadRequest:
      type: object
      properties:
        type:
          type: string
          enum:
            - pfx
            - cert_key
            - combined_pem
            - cert_key_password
          description: "Formato del envío: `pfx`, `cert_key`, `combined_pem` o `cert_key_password`."
        name:
          type: string
          description: Nombre amigable del certificado. Cuando se omite, se deriva de `common_name` o del documento.
        file:
          type: string
          description: Archivo binario (PFX/P12) cuando `type=pfx`, o PEM combinado cuando `type=combined_pem`.
          format: binary
        cert_file:
          type: string
          description: Archivo PEM del certificado (solo para `type=cert_key` o `type=cert_key_password`).
          format: binary
        key_file:
          type: string
          description: Archivo PEM de la clave privada (solo para `type=cert_key` o `type=cert_key_password`).
          format: binary
        password:
          type: string
          description: Contraseña del PFX (`type=pfx`) o de la clave privada (`type=cert_key_password`). Se almacena cifrada y nunca se devuelve.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
      required:
        - type
    CouponTargetV1:
      type: object
      properties:
        plan_ids:
          type: array
          items:
            type: string
            format: uuid
          description: Lista de UUIDs de planes.
        product_ids:
          type: array
          items:
            type: string
            format: uuid
          description: Lista de UUIDs de productos.
    CouponV1:
      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 en su sistema externo, para idempotencia/sincronización.
        code:
          type: string
          description: Código público del cupón — usado por los clientes al aplicar el descuento. Único por organización.
        name:
          type: string
          description: Nombre interno del cupón (mostrado en el panel).
        description:
          type:
            - string
            - "null"
          description: Descripción opcional del cupón.
        discount_type:
          type: string
          enum:
            - percentage
            - fixed_amount
          description: "Tipo de descuento: `percentage` (en puntos porcentuales) o `fixed_amount` (en BRL, ÷100 → BRL)."
        discount_value:
          type: number
          description: Valor del descuento. Cuando `discount_type=percentage`, un entero entre `0` y `100`. Cuando `discount_type=fixed_amount`, el importe en BRL (float, hasta 4 decimales).
          example: 10
        currency:
          type: string
          description: "Moneda ISO 4217. Por defecto: `BRL`."
          example: BRL
        min_purchase:
          type:
            - number
            - "null"
          description: Importe mínimo de la factura (en BRL, ÷100 → BRL) para que el cupón pueda aplicarse.
        max_discount:
          type:
            - number
            - "null"
          description: Tope absoluto del descuento (en BRL, ÷100 → BRL). Se aplica principalmente a cupones porcentuales.
        usage_limit:
          type:
            - integer
            - "null"
          description: Número total de veces que el cupón puede canjearse en toda la organización. `null` = ilimitado.
        usage_limit_per_user:
          type:
            - integer
            - "null"
          description: Número máximo de canjes por cuenta de cobro. `null` = ilimitado.
        usage_count:
          type: integer
          description: Cantidad de canjes ya registrados para el cupón.
          example: 0
        valid_from:
          type:
            - string
            - "null"
          format: date-time
          description: Inicio del periodo de validez (ISO 8601). `null` = sin inicio definido.
        valid_until:
          type:
            - string
            - "null"
          format: date-time
          description: Fin del periodo de validez (ISO 8601). `null` = sin expiración.
        applies_to:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - type:
                - object
                - "null"
              description: Restringe el cupón a planes y/o productos específicos. Cuando es `null`, se aplica a cualquier ítem.
        excludes:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - type:
                - object
                - "null"
              description: Lista de planes y/o productos donde el cupón **no** puede aplicarse.
        is_active:
          type: boolean
          description: Cuando es `false`, el cupón ya no acepta nuevos canjes.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        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
      required:
        - id
        - public_id
        - code
        - name
        - description
        - discount_type
        - discount_value
        - currency
        - min_purchase
        - max_discount
        - usage_limit
        - usage_limit_per_user
        - usage_count
        - valid_from
        - valid_until
        - applies_to
        - excludes
        - is_active
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    CouponListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CouponV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CouponResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CouponV1"
      required:
        - data
    CouponCreateRequest:
      type: object
      properties:
        code:
          type: string
          minLength: 1
          description: Código público del cupón — único por organización.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        name:
          type: string
          minLength: 1
          description: Nombre interno del cupón.
        description:
          type: string
          description: Descripción opcional.
        discount_type:
          type: string
          enum:
            - percentage
            - fixed_amount
          description: "Tipo de descuento: `percentage` o `fixed_amount`."
        discount_value:
          type: number
          minimum: 0
          description: Valor del descuento. Para `percentage`, entero entre `0` y `100`. Para `fixed_amount`, importe en BRL (float, hasta 4 decimales).
        currency:
          type: string
          description: "Moneda ISO 4217. Por defecto: `BRL`."
        min_purchase:
          type: number
          minimum: 0
          description: Importe mínimo de la factura, en BRL (float, hasta 4 decimales), para que el cupón pueda aplicarse.
        max_discount:
          type: number
          minimum: 0
          description: Tope absoluto del descuento, en BRL (float, hasta 4 decimales).
        usage_limit:
          type: integer
          exclusiveMinimum: 0
          description: Máximo total de canjes en la organización. Omite para ilimitado.
        usage_limit_per_user:
          type: integer
          exclusiveMinimum: 0
          description: Máximo de canjes por cuenta de cobro. Omite para ilimitado.
        valid_from:
          type: string
          description: Inicio del periodo de validez (ISO 8601 — fecha o fecha/hora).
        valid_until:
          type: string
          description: Fin del periodo de validez (ISO 8601 — fecha o fecha/hora).
        applies_to:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - description: Restringe el cupón a planes y/o productos.
        excludes:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - description: Lista de planes y/o productos donde el cupón no puede aplicarse.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
      required:
        - code
        - name
        - discount_type
        - discount_value
    CouponUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nuevo nombre interno del cupón.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        description:
          type:
            - string
            - "null"
          description: Nueva descripción. Envía `null` para limpiar.
        usage_limit:
          type:
            - integer
            - "null"
          exclusiveMinimum: 0
          description: Nuevo límite total de canjes. `null` = ilimitado.
        usage_limit_per_user:
          type:
            - integer
            - "null"
          exclusiveMinimum: 0
          description: Nuevo límite por cuenta de cobro. `null` = ilimitado.
        valid_from:
          type:
            - string
            - "null"
          description: Nuevo inicio de validez (ISO 8601). `null` = quita la restricción.
        valid_until:
          type:
            - string
            - "null"
          description: Nuevo fin de validez (ISO 8601). `null` = quita la expiración.
        applies_to:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - type:
                - object
                - "null"
              description: Nueva restricción de planes/productos. `null` = quita la restricción.
        excludes:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - type:
                - object
                - "null"
              description: Nueva lista de exclusiones. `null` = quita las exclusiones.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    CouponRedemptionV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        coupon_id:
          type: string
          format: uuid
          description: UUID del cupón canjeado.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro que aplicó el cupón.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura donde se aplicó el descuento, cuando corresponde.
        discount:
          type: number
          description: Descuento efectivamente aplicado en este canje, en BRL (float, hasta 4 decimales).
        created_at:
          type: string
          format: date-time
      required:
        - id
        - coupon_id
        - billing_account_id
        - invoice_id
        - discount
        - created_at
    CouponRedemptionListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CouponRedemptionV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CreditV1:
      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 en su sistema externo, para idempotencia/sincronización.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro propietaria del crédito.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización (tenant).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID opcional de la `company` vinculada. Cuando está presente, el crédito solo puede aplicarse a facturas de la misma `company`.
        type:
          type: string
          enum:
            - promotional
            - adjustment
            - refund
            - manual
          description: "Tipo del crédito: `promotional`, `adjustment`, `refund` o `manual`."
        amount:
          type: number
          description: Monto original del crédito en BRL (float, hasta 4 decimales).
          example: 100
        amount_remaining:
          type: number
          description: Saldo restante del crédito en BRL (float, hasta 4 decimales).
          example: 100
        currency:
          type: string
          description: "Moneda ISO 4217 (ej.: `BRL`)."
          example: BRL
        description:
          type:
            - string
            - "null"
          description: Descripción libre — se muestra en el extracto y en el audit log.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de expiración (ISO8601). `null` cuando el crédito no expira.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos del crédito.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados validados contra el esquema de la organización.
        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
        applications:
          type: array
          items: {}
          description: Aplicaciones de este crédito en facturas, cuando la relación está cargada.
      required:
        - id
        - public_id
        - external_id
        - billing_account_id
        - organization_id
        - company_id
        - type
        - amount
        - amount_remaining
        - currency
        - description
        - expires_at
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    CreditListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/CreditV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    CreditResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CreditV1"
      required:
        - data
    CreditCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro que recibirá el crédito.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
          description: UUID opcional de la `company` a la que está vinculado el crédito. Cuando se informa, restringe la aplicación del crédito a facturas de la misma `company`.
        type:
          type: string
          enum:
            - promotional
            - adjustment
            - refund
            - manual
          description: "Tipo de crédito: `promotional`, `adjustment`, `refund` o `manual`."
        amount:
          type: number
          exclusiveMinimum: 0
          description: Monto del crédito en BRL (float, hasta 4 decimales). Debe ser un entero positivo.
          example: 100
        description:
          type: string
          maxLength: 500
          description: Descripción libre (hasta 500 caracteres) — se muestra en el extracto y en el audit log.
        expires_at:
          type: string
          format: date-time
          description: Fecha y hora de expiración (ISO8601). Después de esa fecha el saldo restante se descarta.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados validados contra el esquema de la organización.
      required:
        - billing_account_id
        - type
        - amount
    CreditUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador en su sistema externo. Envía `null` para limpiar.
        type:
          type: string
          enum:
            - promotional
            - adjustment
            - refund
            - manual
          description: "Nuevo tipo del crédito: `promotional`, `adjustment`, `refund` o `manual`."
        amount:
          type: number
          exclusiveMinimum: 0
          description: Nuevo monto en BRL (float, hasta 4 decimales). Entero positivo. Solo puede cambiar si el crédito aún no se ha usado.
        description:
          type:
            - string
            - "null"
          maxLength: 500
          description: Nueva descripción. Envía `null` para limpiar.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Nueva fecha de expiración (ISO8601). Envía `null` para eliminar la expiración.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados validados contra el esquema de la organización.
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    CreditDeleteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    InvoiceLineItemV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        invoice_id:
          type: string
          format: uuid
        subscription_item_id:
          type:
            - string
            - "null"
          format: uuid
        product_id:
          type:
            - string
            - "null"
          format: uuid
        price_id:
          type:
            - string
            - "null"
          format: uuid
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
        type:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
          description: Descripción del ítem.
        quantity:
          type: number
          description: Cantidad.
        unit_amount:
          type: number
          description: Valor unitario en BRL (float, hasta 4 decimales).
        amount:
          type: number
          description: Subtotal del ítem en BRL (float, hasta 4 decimales).
        discount:
          type:
            - number
            - "null"
        tax:
          type:
            - number
            - "null"
        period_start:
          type:
            - string
            - "null"
          format: date-time
        period_end:
          type:
            - string
            - "null"
          format: date-time
        proration:
          type:
            - boolean
            - "null"
        proration_details: {}
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
      required:
        - id
        - invoice_id
        - quantity
        - unit_amount
        - amount
        - created_at
    InvoiceInstallmentV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type:
            - string
            - "null"
        invoice_id:
          type: string
          format: uuid
        number:
          type: integer
          description: Número secuencial de la parcela (comienza en 1).
        amount:
          type: number
          description: Valor bruto (fiscal) de la parcela en BRL (float, hasta 4 decimales). La suma de las parcelas es el total de la factura. El importe a pagar es `net`.
        credit_applied:
          type: number
          description: "Parte de la parcela ya cubierta por créditos de la cuenta, en BRL (float, hasta 4 decimales). Los créditos aplicados a la factura se distribuyen FIFO: la primera parcela se cubre primero y el excedente pasa a la siguiente. El importe a pagar es `net`."
        withheld:
          type: number
          description: Parte de las retenciones de la factura (impuestos retenidos en la fuente por el cliente) que corresponde a la parcela, en BRL (float, hasta 4 decimales). Las retenciones se prorratean proporcionalmente al valor de cada parcela, en centavos enteros, con el residuo del redondeo en la primera parcela. Este importe no se cobra al cliente.
        net:
          type: number
          description: "Importe a pagar de la parcela en BRL: `amount − withheld − credit_applied` (float, hasta 4 decimales). Es el importe que exige `POST /invoices/{id}/pay` al seleccionar la parcela."
        due_date:
          type: string
          format: date-time
          description: Fecha de vencimiento de la parcela.
        status:
          type: string
          enum:
            - pending
            - paid
            - canceled
          description: "Estado de la parcela: `pending`, `paid` o `canceled`."
        payment_id:
          type:
            - string
            - "null"
          format: uuid
        paid_at:
          type:
            - string
            - "null"
          format: date-time
        late_fine_received:
          type: number
          description: Multa por atraso recibida en esta cuota, en reales. Cada cuota vence y acumula cargo por su cuenta.
        late_interest_received:
          type: number
          description: Intereses de mora recibidos en esta cuota, en reales.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - invoice_id
        - number
        - amount
        - credit_applied
        - withheld
        - net
        - due_date
        - status
        - created_at
        - updated_at
    InvoiceV1:
      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 en su sistema externo, para idempotencia/sincronización.
        number:
          type:
            - string
            - "null"
          description: Número humano-legible de la factura (generado al finalizar).
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro destino.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora (opcional — por defecto la `default_company` de la organización).
        subscription_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la suscripción de origen, cuando la factura proviene de una suscripción.
        product_group_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del grupo de productos, cuando la factura está restringida a un grupo.
        status:
          type: string
          enum:
            - draft
            - open
            - paid
            - void
            - uncollectible
          description: "Estado: `draft`, `open`, `paid`, `void` o `uncollectible`."
        collection_method:
          type: string
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
          description: "Método de cobro: `charge_automatically`, `manual_charge` o `manual_invoice`."
        currency:
          type: string
          description: "Moneda ISO 4217 (ej.: `BRL`)."
          example: BRL
        subtotal:
          type: number
          description: Suma de los ítems de línea en BRL (float, hasta 4 decimales).
        discount:
          type: number
          description: Descuento aplicado en BRL (float, hasta 4 decimales).
        tax:
          type: number
          description: Impuestos calculados en BRL (float, hasta 4 decimales).
        total_withheld:
          type: number
          description: Total de retenciones tributarias (IRRF/ISS/INSS/CSRF) en BRL.
        net_value:
          type:
            - number
            - "null"
          description: Valor neto tras retenciones, en BRL.
        total:
          type: number
          description: Total de la factura en BRL (float, hasta 4 decimales).
        amount_due:
          type: number
          description: Valor debido (cobrado) en BRL.
        amount_paid:
          type: number
          description: Valor ya pagado en BRL.
        amount_remaining:
          type: number
          description: Valor restante a pagar en BRL.
        late_fine_received:
          type: number
          description: Multa por atraso efectivamente recibida, en reales. Acumulada; no entra en `total`, porque la multa es ingreso financiero y queda fuera de la base de cálculo de la NFe.
        late_interest_received:
          type: number
          description: Intereses de mora efectivamente recibidos, en reales. Acumulados; no entran en `total`, por la misma razón que la multa.
        late_fee_policy_id:
          type:
            - string
            - "null"
          format: uuid
          description: Política de intereses y multas de esta factura. Nulo hereda de la suscripción, luego de la cuenta de cobro, luego del valor por defecto de la organización. Al finalizar, la factura congela la política vigente, de modo que una renegociación posterior no altera lo que cobra.
        period_start:
          type:
            - string
            - "null"
          format: date-time
          description: Inicio del período de competencia (facturas de suscripción).
        period_end:
          type:
            - string
            - "null"
          format: date-time
          description: Fin del período de competencia (facturas de suscripción).
        due_date:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha de vencimiento.
        paid_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora en que la factura fue saldada.
        voided_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora en que la factura fue cancelada (`void`).
        finalized_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora en que la factura salió del borrador (`draft` → `open`).
        billing_reason:
          type:
            - string
            - "null"
          description: "Motivo de generación: `subscription_cycle`, `subscription_create`, `manual`, etc."
        description:
          type:
            - string
            - "null"
          description: Descripción libre mostrada al inicio de la factura.
        footer:
          type:
            - string
            - "null"
          description: Pie libre mostrado al final de la factura.
        hosted_invoice_url:
          type:
            - string
            - "null"
          description: URL pública alojada de la factura.
        invoice_pdf_url:
          type:
            - string
            - "null"
          description: URL directa al PDF de la factura.
        next_payment_attempt:
          type:
            - string
            - "null"
          format: date-time
          description: Próximo intento de cobro automático (dunning).
        payment_attempts:
          type: integer
          description: Cantidad de intentos de cobro realizados.
        installment_count:
          type:
            - integer
            - "null"
          description: Cantidad de parcelas (cuando la factura está dividida).
        nfe_issuance_policy:
          type:
            - string
            - "null"
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
          description: "Política de emisión de NF-e: `disabled`, `on_finalization`, `on_full_payment` o `per_installment`."
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados definidos por la organización.
        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
        line_items:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceLineItemV1"
          description: Ítems de línea — presente cuando se incluye vía `include=line_items`.
        installments:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceInstallmentV1"
          description: Parcelas — presente cuando se incluye vía `include=installments`.
      required:
        - id
        - public_id
        - external_id
        - number
        - billing_account_id
        - company_id
        - subscription_id
        - product_group_id
        - status
        - collection_method
        - currency
        - subtotal
        - discount
        - tax
        - total_withheld
        - net_value
        - total
        - amount_due
        - amount_paid
        - amount_remaining
        - late_fine_received
        - late_interest_received
        - late_fee_policy_id
        - period_start
        - period_end
        - due_date
        - paid_at
        - voided_at
        - finalized_at
        - billing_reason
        - description
        - footer
        - hosted_invoice_url
        - invoice_pdf_url
        - next_payment_attempt
        - payment_attempts
        - installment_count
        - nfe_issuance_policy
        - metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    InvoiceListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    InvoiceResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/InvoiceV1"
      required:
        - data
    InvoiceLineItemCreateInput:
      type: object
      properties:
        description:
          type: string
          minLength: 1
          description: Descripción del ítem. **Obligatorio**.
        quantity:
          type: number
          minimum: 1
          description: "Cantidad. Por defecto: 1."
        unit_amount:
          type: number
          minimum: 0
          description: Valor unitario en BRL.
        product_id:
          type: string
          format: uuid
          description: UUID del producto (opcional).
        price_id:
          type: string
          format: uuid
          description: UUID del precio (opcional).
        service_item_id:
          type: string
          format: uuid
          description: UUID del ítem de servicio (opcional).
      required:
        - description
        - unit_amount
    InvoiceInstallmentCreateInput:
      type: object
      properties:
        amount:
          type: number
          exclusiveMinimum: 0
          description: Valor de la parcela en BRL.
        due_date:
          type: string
          description: Fecha de vencimiento de la parcela.
      required:
        - amount
        - due_date
    InvoiceCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro destino. **Obligatorio**.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
          description: "UUID de la empresa emisora. Por defecto: empresa por defecto de la organización."
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción de origen.
        product_group_id:
          type: string
          format: uuid
          description: UUID del grupo de productos.
        collection_method:
          type: string
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
          description: "Método de cobro. Por defecto: `manual_invoice`."
        due_date:
          type: string
          description: "Fecha de vencimiento. Por defecto: hoy + `payment_terms_days` de la cuenta."
        description:
          type: string
          description: Descripción libre mostrada al inicio de la factura.
        footer:
          type: string
          description: Pie libre mostrado al final de la factura.
        line_items:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceLineItemCreateInput"
          minItems: 1
          maxItems: 200
          description: Ítems de línea. Mínimo 1.
        discount:
          type: number
          minimum: 0
          description: Descuento fijo en BRL.
        discount_description:
          type: string
          description: 'Descripción del descuento (ej.: "Descuento por pago anual (20%)").'
        installments:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceInstallmentCreateInput"
          minItems: 2
          maxItems: 60
          description: Cronograma de parcelas (mínimo 2). Cada ítem tiene `amount` y `due_date`.
        nfe_issuance_policy:
          type: string
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
          description: Política de emisión de NF-e para facturas en cuotas.
        period_start:
          type: string
          description: Inicio del período de competencia (autocompletado en facturas de suscripción).
        period_end:
          type: string
          description: Fin del período de competencia (autocompletado en facturas de suscripción).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
      required:
        - billing_account_id
        - line_items
    InvoiceLineItemUpdateInput:
      type: object
      properties:
        id:
          type: string
          format: uuid
        description:
          type: string
          minLength: 1
        quantity:
          type: number
          minimum: 1
        unit_amount:
          type: number
          minimum: 0
      required:
        - description
        - unit_amount
    InvoiceUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador en su sistema externo. Usa `null` para limpiar.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Actualiza la empresa emisora. Usa `null` para limpiar.
        collection_method:
          type: string
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
          description: Actualiza el método de cobro.
        due_date:
          type: string
          description: Actualiza la fecha de vencimiento.
        period_start:
          type:
            - string
            - "null"
          description: Actualiza el inicio del período de competencia. Usa `null` para limpiar.
        period_end:
          type:
            - string
            - "null"
          description: Actualiza el fin del período de competencia. Usa `null` para limpiar.
        description:
          type: string
        footer:
          type: string
        line_items:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceLineItemUpdateInput"
          maxItems: 200
          description: Sustituye los ítems de línea. Para preservar un ítem, envía su `id`.
        nfe_issuance_policy:
          type:
            - string
            - "null"
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
          description: Actualiza la política de NF-e. Usa `null` para limpiar.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    InvoiceVoidRequest:
      type: object
      properties:
        reason:
          type: string
          description: Motivo de la cancelación (registrado en el audit log).
    InvoiceUndoPaymentRequest:
      type: object
      properties:
        reason:
          type: string
          description: Motivo de la reversión (registrado en el audit log).
    InvoicePayRequest:
      type: object
      properties:
        payment_method:
          type: string
          enum:
            - pix
            - bank_slip
            - card
            - bank_transfer
          description: Cuando se informa, dispara el gateway (`pix`, `bank_slip` o `card`) o crea un cobro por transferencia (`bank_transfer`, exige `bank_account_id` o `pix_key_id`). Omite para marcar como pagada manualmente.
        payment_method_id:
          type: string
          format: uuid
          description: "UUID de un método de pago guardado (ej.: tarjeta tokenizada)."
        card:
          type: object
          properties:
            card_token:
              type: string
              minLength: 1
              description: Token de la tarjeta obtenido en el front-end vía el SDK del gateway.
            holder_name:
              type: string
              minLength: 3
              description: Nombre impreso en la tarjeta (mínimo 3 caracteres).
          required:
            - card_token
            - holder_name
          description: Datos de la tarjeta cuando `payment_method = card` y no hay `payment_method_id`.
        bank_account_id:
          type: string
          format: uuid
          description: "Con `payment_method = bank_transfer`: UUID de la cuenta bancaria de la organización a la que el cliente debe transferir (vea `/bank_accounts`). Informe este o `pix_key_id`, nunca los dos."
        pix_key_id:
          type: string
          format: uuid
          description: "Con `payment_method = bank_transfer`: UUID de la clave Pix de la organización a la que el cliente debe transferir (vea `/pix_keys`). Informe este o `bank_account_id`, nunca los dos."
        amount:
          type: number
          exclusiveMinimum: 0
          description: "Valor a cobrar en BRL. Por defecto: valor restante de la factura. Obligatorio cuando se informa `installment_ids`, y debe ser igual a la suma del `net` de las parcelas seleccionadas."
        installment_ids:
          type: array
          items:
            type: string
            format: uuid
          description: UUIDs de las parcelas que el pago cubre (facturas en cuotas).
    InvoicePayResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    InvoiceApplyCreditsRequest:
      type: object
      properties:
        credit_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: UUIDs de los créditos a aplicar (mínimo 1).
        amount:
          type: number
          exclusiveMinimum: 0
          description: "Valor a aplicar en BRL. Por defecto: cubre toda la factura."
      required:
        - credit_ids
    InvoiceCreditsResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    InvoiceNfeResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    InvoicePaymentMethodsResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            invoice_id:
              type: string
              format: uuid
            methods:
              type: array
              items:
                type: string
                enum:
                  - card
                  - bank_slip
                  - pix
                  - bank_transfer
            details:
              type: array
              items:
                type: object
                properties:
                  type:
                    type: string
                    enum:
                      - card
                      - bank_slip
                      - pix
                      - bank_transfer
                  gateway_id:
                    type:
                      - string
                      - "null"
                    format: uuid
                  gateway_name:
                    type:
                      - string
                      - "null"
                  is_default:
                    type: boolean
                required:
                  - type
                  - gateway_id
                  - gateway_name
                  - is_default
            pagarme_public_key:
              type: string
          required:
            - invoice_id
            - methods
            - details
      required:
        - data
    InvoiceInstallmentsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceInstallmentV1"
      required:
        - data
    InvoiceInstallmentsCreateRequest:
      type: object
      properties:
        installments:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceInstallmentCreateInput"
          minItems: 2
          maxItems: 60
          description: Lista de parcelas. Mínimo 2.
      required:
        - installments
    InvoiceInstallmentResponse:
      type: object
      properties:
        data:
          allOf:
            - $ref: "#/components/schemas/InvoiceInstallmentV1"
            - type:
                - object
                - "null"
      required:
        - data
    InvoiceInstallmentPayRequest:
      type: object
      properties:
        payment_method:
          type: string
          enum:
            - pix
            - bank_slip
            - card
            - bank_transfer
          description: Cuando se informa, dispara el gateway (`pix`, `bank_slip` o `card`) o crea un cobro por transferencia (`bank_transfer`, exige `bank_account_id` o `pix_key_id`). Omite para marcar como pagada manualmente.
        payment_method_id:
          type: string
          format: uuid
          description: "UUID de un método de pago guardado (ej.: tarjeta tokenizada)."
        card:
          type: object
          properties:
            card_token:
              type: string
              minLength: 1
              description: Token de la tarjeta obtenido en el front-end vía el SDK del gateway.
            holder_name:
              type: string
              minLength: 3
              description: Nombre impreso en la tarjeta (mínimo 3 caracteres).
          required:
            - card_token
            - holder_name
          description: Datos de la tarjeta cuando `payment_method = card` y no hay `payment_method_id`.
        bank_account_id:
          type: string
          format: uuid
          description: "Con `payment_method = bank_transfer`: UUID de la cuenta bancaria de la organización a la que el cliente debe transferir (vea `/bank_accounts`). Informe este o `pix_key_id`, nunca los dos."
        pix_key_id:
          type: string
          format: uuid
          description: "Con `payment_method = bank_transfer`: UUID de la clave Pix de la organización a la que el cliente debe transferir (vea `/pix_keys`). Informe este o `bank_account_id`, nunca los dos."
      required:
        - payment_method
    InvoiceDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    PaymentV1:
      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 en su sistema externo, para idempotencia/sincronización.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura asociada, cuando exista.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora.
        payment_method_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del medio de pago utilizado.
        gateway_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del gateway que procesó el pago.
        bank_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta bancaria de la organización indicada al cliente en un cobro `bank_transfer`. Los datos enviados quedan congelados en `metadata.transfer`.
        pix_key_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la clave Pix de la organización indicada al cliente en un cobro `bank_transfer`. Los datos enviados quedan congelados en `metadata.transfer`.
        payment_method_type:
          type:
            - string
            - "null"
          enum:
            - card
            - bank_slip
            - pix
            - bank_transfer
          description: "Tipo del medio de pago: `card`, `bank_slip`, `pix` o `bank_transfer`."
        amount:
          type: number
          description: Monto cobrado en BRL (float, hasta 4 decimales).
          example: 100
        principal_amount:
          type:
            - number
            - "null"
          description: Parte de `paid_amount` que redujo el saldo de la factura. Esta es la porción que cuenta como ingreso por servicio — multa e intereses son ingreso financiero. Nulo en pagos liquidados antes de existir el desglose, donde `paid_amount` ERA el principal.
        fine_amount:
          type: number
          description: Multa por atraso contenida en `paid_amount`, en reales.
        interest_amount:
          type: number
          description: Intereses de mora contenidos en `paid_amount`, en reales.
        discount_amount:
          type: number
          description: Descuento o rebaja concedida en la liquidación, en reales.
        paid_amount:
          type:
            - number
            - "null"
          description: Monto efectivamente recibido en BRL (float, hasta 4 decimales).
        currency:
          type: string
          description: "Moneda ISO 4217 (ej.: `BRL`)."
          example: BRL
        status:
          type: string
          enum:
            - pending
            - processing
            - succeeded
            - failed
            - canceled
            - partial
            - refunded
            - partially_refunded
          description: "Estado: `pending`, `processing`, `succeeded`, `failed`, `canceled`, `partial`, `refunded` o `partially_refunded`."
        payment_gateway:
          type:
            - string
            - "null"
          description: "Nombre del gateway upstream (ej.: `KOBANA`, `PAGARME`)."
        gateway_payment_id:
          type:
            - string
            - "null"
          description: Identificador del pago en el gateway upstream.
        failure_code:
          type:
            - string
            - "null"
          description: Código de falla devuelto por el gateway.
        failure_message:
          type:
            - string
            - "null"
          description: Mensaje de falla devuelto por el gateway.
        idempotency_key:
          type:
            - string
            - "null"
          description: Clave de idempotencia provista al crear el pago.
        paid_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora de la confirmación del pago.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el 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
      required:
        - id
        - public_id
        - external_id
        - invoice_id
        - billing_account_id
        - company_id
        - payment_method_id
        - gateway_id
        - bank_account_id
        - pix_key_id
        - payment_method_type
        - amount
        - principal_amount
        - fine_amount
        - interest_amount
        - discount_amount
        - paid_amount
        - currency
        - status
        - payment_gateway
        - gateway_payment_id
        - failure_code
        - failure_message
        - idempotency_key
        - paid_at
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    PaymentListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PaymentV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PaymentResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PaymentV1"
      required:
        - data
    PaymentCreateCard:
      type: object
      properties:
        card_token:
          type: string
          minLength: 1
          description: Token de tarjeta emitido por el gateway (preferido).
        number:
          type: string
          minLength: 13
          maxLength: 19
          description: Número de la tarjeta (PAN). Use el token siempre que sea posible.
        exp_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de expiración (1–12).
        exp_year:
          type: integer
          description: Año de expiración (≥ año actual).
        cvv:
          type: string
          minLength: 3
          maxLength: 4
          description: CVV/CVC de la tarjeta (3 a 4 dígitos).
        holder_name:
          type: string
          minLength: 1
          description: Nombre del portador tal como aparece en la tarjeta.
      required:
        - holder_name
    PaymentCreatePaymentMethod:
      type: object
      properties:
        type:
          type: string
          enum:
            - card
            - bank_slip
            - pix
          description: "Tipo del medio de pago: `card`, `bank_slip` o `pix`."
        card:
          allOf:
            - $ref: "#/components/schemas/PaymentCreateCard"
            - description: Datos de la tarjeta — token (preferido) **o** PAN/expiración/CVV.
      required:
        - type
    PaymentCreateRequest:
      type: object
      properties:
        invoice_id:
          type: string
          format: uuid
          description: UUID de la factura a pagar.
        payment_method_id:
          type: string
          format: uuid
          description: UUID de un medio de pago previamente registrado para la cuenta.
        payment_method:
          allOf:
            - $ref: "#/components/schemas/PaymentCreatePaymentMethod"
            - description: Bloque con datos del medio de pago — usado cuando no hay `payment_method_id`.
        amount:
          type: number
          exclusiveMinimum: 0
          description: "Monto a cobrar en BRL (float, hasta 4 decimales). Por defecto: saldo abierto de la factura."
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente para correlación interna.
      required:
        - invoice_id
    PaymentCancelRequest:
      type: object
      properties:
        reason:
          type: string
          description: Motivo de la cancelación (registrado en el audit log).
        cancel_on_gateway:
          type: boolean
          description: Cuando es `true` (por defecto), también cancela en el gateway upstream.
    PaymentRetryCard:
      type: object
      properties:
        card_token:
          type: string
          minLength: 1
          description: Token de tarjeta emitido por el gateway.
        holder_name:
          type: string
          minLength: 3
          description: Nombre del portador tal como aparece en la tarjeta.
      required:
        - card_token
        - holder_name
    PaymentRetryRequest:
      type: object
      properties:
        card:
          allOf:
            - $ref: "#/components/schemas/PaymentRetryCard"
            - description: Tarjeta alternativa (token y portador) para el reintento.
        payment_method_id:
          type: string
          format: uuid
          description: UUID de un medio de pago guardado para usar en el reintento.
    PaymentChangeCardRequest:
      type: object
      properties:
        credit_card_id:
          type: string
          format: uuid
          description: UUID de la tarjeta de crédito activa de la cuenta de cobro.
      required:
        - credit_card_id
    PaymentChangeDueDateRequest:
      type: object
      properties:
        due_date:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: Nueva fecha de vencimiento en formato `YYYY-MM-DD`.
          example: 2026-08-15
      required:
        - due_date
    PaymentChangeDueDateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            due_date:
              type: string
            updated:
              type: boolean
          required:
            - due_date
            - updated
      required:
        - data
    PaymentSendEmailRequest:
      type: object
      properties:
        email:
          type: string
          format: email
          description: Dirección de correo del destinatario.
        message:
          type: string
          description: Mensaje opcional incluido en el cuerpo del correo.
      required:
        - email
    PaymentSendEmailResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            sent:
              type: boolean
            email:
              type: string
              format: email
          required:
            - sent
            - email
      required:
        - data
    PaymentRefundRequest:
      type: object
      properties:
        amount:
          type: number
          exclusiveMinimum: 0
          description: "Monto a reembolsar en BRL (float, hasta 4 decimales). Por defecto: monto total del pago."
        reason:
          type: string
          description: Motivo del reembolso (registrado en el audit log).
    PaymentBulkUpdateInvoiceRequest:
      type: object
      properties:
        payment_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: Lista de UUIDs de los pagos a actualizar.
        invoice_id:
          type: string
          format: uuid
          description: UUID de la factura de destino.
      required:
        - payment_ids
        - invoice_id
    PaymentBulkUpdateInvoiceResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            updated_count:
              type: integer
          required:
            - updated_count
      required:
        - data
    PaymentDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    PaymentMethodCreditCardV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del registro de tarjeta.
        status:
          type: string
          enum:
            - active
            - expired
            - removed
          description: "Estado de la tarjeta: `active`, `expired`, `removed`."
        brand:
          type:
            - string
            - "null"
          description: "Marca de la tarjeta (ej.: `visa`, `mastercard`)."
          example: visa
        last_four_digits:
          type:
            - string
            - "null"
          description: Últimos cuatro dígitos de la tarjeta.
          example: "4242"
        holder_name:
          type:
            - string
            - "null"
          description: Nombre del titular como aparece en la tarjeta.
        expiration_month:
          type:
            - integer
            - "null"
          description: Mes de vencimiento (1–12).
          example: 12
        expiration_year:
          type:
            - integer
            - "null"
          description: Año de vencimiento (4 dígitos).
          example: 2030
      required:
        - id
        - status
        - brand
        - last_four_digits
        - holder_name
        - expiration_month
        - expiration_year
    PaymentMethodBankAccountV1:
      type: object
      properties:
        bank_code:
          type:
            - string
            - "null"
          description: Código de compensación del banco (FEBRABAN, 3 dígitos).
          example: "341"
        bank_name:
          type:
            - string
            - "null"
          description: Nombre del banco, resuelto a partir del `bank_code`.
          example: Itaú
        agency:
          type:
            - string
            - "null"
          description: Agencia bancaria.
        account:
          type:
            - string
            - "null"
          description: Número de la cuenta bancaria.
        account_type:
          type:
            - string
            - "null"
          enum:
            - checking
            - savings
          description: "Tipo de cuenta: `checking` o `savings`."
        holder_name:
          type:
            - string
            - "null"
          description: Nombre del titular de la cuenta.
      required:
        - bank_code
        - bank_name
        - agency
        - account
        - account_type
        - holder_name
    PaymentMethodV1:
      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 en su sistema externo, para idempotencia/sincronización.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro propietaria.
        credit_card_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del `credit_card` asociado, cuando `type=card`.
        type:
          type: string
          enum:
            - card
            - bank_slip
            - pix
            - bank_transfer
          description: "Tipo del método: `card`, `bank_slip`, `pix` o `bank_transfer`."
        status:
          type: string
          enum:
            - active
            - expired
            - failed
            - removed
          description: "Estado del método: `active`, `expired`, `failed` o `removed`."
        is_default:
          type: boolean
          description: Indica si este es el método predeterminado de la cuenta de cobro.
        is_backup:
          type: boolean
          description: Indica si el método se usa como respaldo del predeterminado.
        billing_details:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Datos de cobro opcionales (nombre, correo, teléfono, dirección) enviados al gateway.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        bank_account:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBankAccountV1"
            - description: Resumen público de la cuenta bancaria, presente cuando `type=bank_transfer`. No incluye el documento del titular.
        credit_card:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodCreditCardV1"
            - description: Resumen público de la tarjeta, presente cuando `type=card`. No incluye tokens del gateway ni fingerprint.
      required:
        - id
        - public_id
        - external_id
        - billing_account_id
        - credit_card_id
        - type
        - status
        - is_default
        - is_backup
        - created_at
        - updated_at
    PaymentMethodListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PaymentMethodV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PaymentMethodResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PaymentMethodV1"
      required:
        - data
    PaymentMethodCardInput:
      type: object
      properties:
        card_token:
          type: string
          minLength: 1
          description: Token de la tarjeta generado por la tokenización del lado del cliente del gateway.
        holder_name:
          type: string
          minLength: 1
          description: Nombre del titular como aparece en la tarjeta.
      required:
        - card_token
        - holder_name
    PaymentMethodBankAccountInput:
      type: object
      properties:
        bank_code:
          type: string
          minLength: 3
          maxLength: 3
          description: Código de compensación del banco (FEBRABAN, 3 dígitos).
          example: "341"
        agency:
          type: string
          minLength: 1
          description: Agencia bancaria.
        account:
          type: string
          minLength: 1
          description: Número de la cuenta bancaria.
        account_type:
          type: string
          enum:
            - checking
            - savings
          description: "Tipo de cuenta: `checking` o `savings`."
        holder_name:
          type: string
          minLength: 1
          description: Nombre del titular de la cuenta.
        holder_document:
          type: string
          minLength: 11
          maxLength: 14
          description: CPF o CNPJ del titular (11 a 14 dígitos).
      required:
        - bank_code
        - agency
        - account
        - account_type
        - holder_name
        - holder_document
    PaymentMethodBillingAddress:
      type: object
      properties:
        street:
          type: string
        number:
          type: string
        complement:
          type: string
        neighborhood:
          type: string
        city:
          type: string
        state:
          type: string
          minLength: 2
          maxLength: 2
        zip_code:
          type: string
        country:
          type: string
      required:
        - street
        - number
        - neighborhood
        - city
        - state
        - zip_code
    PaymentMethodBillingDetailsInput:
      type: object
      properties:
        name:
          type: string
          description: Nombre para los datos de cobro.
        email:
          type: string
          format: email
          description: Correo para los datos de cobro.
        phone:
          type: string
          description: Teléfono para los datos de cobro.
        address:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBillingAddress"
            - description: Dirección de cobro.
    PaymentMethodCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro propietaria del método de pago.
        type:
          type: string
          enum:
            - card
            - bank_slip
            - pix
            - bank_transfer
          description: "Tipo del método: `card`, `bank_slip`, `pix` o `bank_transfer`."
        is_default:
          type: boolean
          description: Cuando es `true`, marca este método como predeterminado de la cuenta (desmarca los anteriores). El primer método creado para una cuenta también se vuelve predeterminado automáticamente.
        card:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodCardInput"
            - description: Bloque de tarjeta. Obligatorio cuando `type=card`.
        bank_account:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBankAccountInput"
            - description: Bloque de cuenta bancaria. Obligatorio cuando `type=bank_transfer`.
        billing_details:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBillingDetailsInput"
            - description: Datos de cobro opcionales (nombre, correo, teléfono, dirección) usados por el gateway.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
      required:
        - billing_account_id
        - type
    PaymentMethodUpdateRequest:
      type: object
      properties:
        exp_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de vencimiento de la tarjeta (1–12).
        exp_year:
          type: integer
          description: Año de vencimiento de la tarjeta (>= año actual).
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
      required:
        - exp_month
        - exp_year
    NfeV1:
      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 en su sistema externo, para idempotencia/sincronización.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura vinculada (cuando la NF-e se emitió para una factura).
        transaction_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la transacción de origen, cuando corresponda.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro (tomador) de la NF-e.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización emisora.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora (prestador). Opcional cuando la organización tiene empresa por defecto.
        person_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la persona (tomador) asociada a la NF-e.
        status:
          type: string
          enum:
            - draft
            - pending
            - processing
            - issued
            - pending_cancel
            - canceling
            - canceled
            - error
          description: "Estado: `draft`, `pending`, `processing`, `issued`, `pending_cancel`, `canceling`, `canceled` o `error`."
        nfe_number:
          type:
            - integer
            - "null"
          description: Número de la NF-e asignado por la municipalidad (establecido tras la emisión).
        nfe_series:
          type:
            - string
            - "null"
          description: Serie de la NF-e.
        nfe_key:
          type:
            - string
            - "null"
          description: Clave de acceso única de la NF-e (44 o 50 dígitos, según el municipio).
        verification_code:
          type:
            - string
            - "null"
          description: Código de verificación/autenticidad impreso en el DANFSE.
        issue_date:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de emisión por la municipalidad.
        cancelled_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de la cancelación (cuando corresponda).
        amount:
          type: number
          description: Monto de la NF-e en BRL (float, hasta 4 decimales).
        service_code:
          type:
            - string
            - "null"
          description: Código del servicio según la tabla municipal.
        service_description:
          type:
            - string
            - "null"
          description: Descripción libre del servicio prestado.
        lc116_code:
          type:
            - string
            - "null"
          description: Código LC 116 (lista nacional de servicios).
        cnae_code:
          type:
            - string
            - "null"
          description: Código CNAE de la actividad.
        nbs_code:
          type:
            - string
            - "null"
          description: Código NBS (Nomenclatura Brasileña de Servicios).
        ncm_code:
          type:
            - string
            - "null"
          description: Código NCM (Nomenclatura Común del Mercosur), cuando corresponda.
        c_class_trib:
          type:
            - string
            - "null"
          description: Clasificación Tributaria (cClassTrib) del IBS/CBS, requerida junto al código de servicio/NBS por la reforma tributaria (Anexo VIII).
        ind_op:
          type:
            - string
            - "null"
          description: Indicador de Operación (indOp) del IBS/CBS en la NFS-e nacional (SNNFSE).
        customer_snapshot:
          type: object
          additionalProperties: {}
          description: Instantánea de los datos del tomador al momento de la emisión (nombre, documento, dirección).
        taxes:
          type: object
          additionalProperties: {}
          description: Alícuotas y montos de impuestos (ISS, PIS, COFINS, CSLL, IR, INSS).
        xml_url:
          type:
            - string
            - "null"
          description: URL pública para el XML alojado por el proveedor.
        pdf_url:
          type:
            - string
            - "null"
          description: URL pública para el PDF (DANFE/DANFSE) alojado por el proveedor.
        provider_company_id:
          type:
            - string
            - "null"
          description: Identificador de la empresa en el proveedor externo.
        rps_number:
          type:
            - integer
            - "null"
          description: Número del RPS (Recibo Provisorio de Servicios).
        rps_serial_number:
          type:
            - string
            - "null"
          description: Serie del RPS.
        issue_attempts:
          type: integer
          description: Cantidad de intentos de emisión realizados.
        cancel_attempts:
          type: integer
          description: Cantidad de intentos de cancelación realizados.
        next_retry_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora del próximo reintento automático (emisión o cancelación).
        error_message:
          type:
            - string
            - "null"
          description: Mensaje de error devuelto por el proveedor en el último intento.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados definidos por la organización.
        pdf_downloaded_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha en que el PDF fue descargado y persistido en la base de datos.
        xml_downloaded_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha en que el XML fue descargado y persistido en la base de datos.
        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
      required:
        - id
        - public_id
        - external_id
        - invoice_id
        - transaction_id
        - billing_account_id
        - organization_id
        - company_id
        - person_id
        - status
        - nfe_number
        - nfe_series
        - nfe_key
        - verification_code
        - issue_date
        - cancelled_at
        - amount
        - service_code
        - service_description
        - lc116_code
        - cnae_code
        - nbs_code
        - ncm_code
        - c_class_trib
        - ind_op
        - customer_snapshot
        - taxes
        - xml_url
        - pdf_url
        - provider_company_id
        - rps_number
        - rps_serial_number
        - issue_attempts
        - cancel_attempts
        - next_retry_at
        - error_message
        - metadata
        - pdf_downloaded_at
        - xml_downloaded_at
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    NfeListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/NfeV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    NfeResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/NfeV1"
      required:
        - data
    NfeCustomerAddressInput:
      type: object
      properties:
        street:
          type: string
          description: Calle.
        number:
          type: string
          description: Número de la dirección.
        complement:
          type: string
          description: Complemento (opcional).
        neighborhood:
          type: string
          description: Barrio.
        city:
          type: string
          description: Ciudad.
        city_code:
          type: string
          description: Código IBGE de la ciudad (opcional).
        state:
          type: string
          description: Estado (sigla de dos letras).
        zip_code:
          type: string
          description: Código postal.
        country:
          type: string
          description: País (opcional, por defecto `BR`).
      required:
        - street
        - number
        - neighborhood
        - city
        - state
        - zip_code
      description: Dirección del tomador.
    NfeCustomerInput:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre o razón social del tomador.
        email:
          type: string
          format: email
          description: Correo del tomador.
        document_type:
          type: string
          enum:
            - cpf
            - cnpj
          description: "Tipo de documento: `cpf` o `cnpj`."
        document_number:
          type: string
          minLength: 1
          description: Número del documento (solo dígitos o con formato).
        phone:
          type: string
          description: Teléfono del tomador.
        address:
          $ref: "#/components/schemas/NfeCustomerAddressInput"
      required:
        - name
        - email
        - document_type
        - document_number
      description: Datos del tomador al momento de la emisión. **Obligatorio**.
    NfeTaxesInput:
      type: object
      properties:
        iss_rate:
          type: number
          description: Alícuota de ISS (decimal).
        pis_rate:
          type: number
          description: Alícuota de PIS (decimal).
        cofins_rate:
          type: number
          description: Alícuota de COFINS (decimal).
        csll_rate:
          type: number
          description: Alícuota de CSLL (decimal).
        ir_rate:
          type: number
          description: Alícuota de IR (decimal).
        inss_rate:
          type: number
          description: Alícuota de INSS (decimal).
      description: "Alícuotas de impuestos (en decimal, ej.: `0.05` para 5%). Aplica los defaults de la empresa cuando se omite."
    NfeCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro (tomador). **Obligatorio**.
        company_id:
          type: string
          format: uuid
          description: "UUID de la empresa emisora (prestador). Por defecto: empresa por defecto de la organización."
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        invoice_id:
          type: string
          format: uuid
          description: UUID de la factura vinculada (opcional).
        transaction_id:
          type: string
          format: uuid
          description: UUID de la transacción de origen (opcional).
        amount:
          type: number
          exclusiveMinimum: 0
          description: Monto de la NF-e en BRL (float, hasta 4 decimales). **Obligatorio**, debe ser positivo.
        service_code:
          type: string
          description: Código del servicio según la tabla municipal.
        service_description:
          type: string
          description: Descripción libre del servicio prestado.
        lc116_code:
          type: string
          description: Código LC 116.
        cnae_code:
          type: string
          description: Código CNAE.
        nbs_code:
          type: string
          description: Código NBS.
        c_class_trib:
          type: string
          description: Clasificación Tributaria (cClassTrib) del IBS/CBS.
        ind_op:
          type: string
          description: Indicador de Operación (indOp) del IBS/CBS.
        rps_number:
          type: integer
          description: Número del RPS (cuando la numeración es gestionada por la aplicación).
        rps_serial_number:
          type: string
          description: Serie del RPS.
        customer:
          $ref: "#/components/schemas/NfeCustomerInput"
        taxes:
          $ref: "#/components/schemas/NfeTaxesInput"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
      required:
        - billing_account_id
        - amount
        - customer
    NfeUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador en su sistema externo. Usa `null` para limpiar.
        service_code:
          type: string
          description: Actualiza el código del servicio.
        service_description:
          type: string
          description: Actualiza la descripción del servicio.
        amount:
          type: number
          exclusiveMinimum: 0
          description: Actualiza el monto de la NF-e en BRL.
        lc116_code:
          type:
            - string
            - "null"
          description: Actualiza el código LC 116. Usa `null` para limpiar.
        cnae_code:
          type:
            - string
            - "null"
          description: Actualiza el código CNAE. Usa `null` para limpiar.
        nbs_code:
          type:
            - string
            - "null"
          description: Actualiza el código NBS. Usa `null` para limpiar.
        ncm_code:
          type:
            - string
            - "null"
          description: Actualiza el código NCM. Usa `null` para limpiar.
        c_class_trib:
          type:
            - string
            - "null"
          description: Actualiza la Clasificación Tributaria (cClassTrib). Usa `null` para limpiar.
        ind_op:
          type:
            - string
            - "null"
          description: Actualiza el Indicador de Operación (indOp). Usa `null` para limpiar.
        rps_number:
          type:
            - integer
            - "null"
          description: Actualiza el número del RPS. Usa `null` para limpiar.
        rps_serial_number:
          type:
            - string
            - "null"
          description: Actualiza la serie del RPS. Usa `null` para limpiar.
        customer_snapshot:
          type: object
          additionalProperties: {}
          description: Sustituye el snapshot del tomador.
        taxes:
          type: object
          additionalProperties: {}
          description: Sustituye las alícuotas y montos de impuestos.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Actualiza los campos personalizados.
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    NfeCancelRequest:
      type: object
      properties:
        reason:
          type: string
          minLength: 15
          description: Motivo de la cancelación. **Mínimo 15 caracteres**. Registrado en el audit log y enviado al proveedor.
      required:
        - reason
    NfeDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    NfeBulkUpdateRequest:
      type: object
      properties:
        nfe_ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          description: UUIDs de las NF-e a actualizar. Mínimo 1.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura a vincular. Envía `null` para desvincular.
      required:
        - nfe_ids
        - invoice_id
    NfeBulkUpdateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            updated:
              type: integer
          required:
            - updated
      required:
        - data
    NfeBulkDeleteRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          maxItems: 100
          description: UUIDs de las NF-e a eliminar. Mínimo 1, máximo 100.
      required:
        - ids
    NfeBulkDeleteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted_count:
              type: integer
          required:
            - deleted_count
      required:
        - data
    NfeSyncOrgResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            job_id:
              type: string
            status:
              type: string
          required:
            - job_id
            - status
      required:
        - data
    NfeRequestTryV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        nfe_id:
          type: string
          format: uuid
        action:
          type: string
          description: "Acción intentada: `issue`, `cancel` o `query`."
        endpoint:
          type: string
          description: Endpoint del proveedor llamado.
        request_body:
          type:
            - string
            - "null"
        response_body:
          type:
            - string
            - "null"
        http_status:
          type:
            - string
            - "null"
          description: Estado HTTP devuelto por el proveedor.
        success:
          type: boolean
        error_message:
          type:
            - string
            - "null"
        duration_ms:
          type:
            - integer
            - "null"
          description: Duración de la solicitud en milisegundos.
        created_at:
          type: string
          format: date-time
      required:
        - id
        - nfe_id
        - action
        - endpoint
        - request_body
        - response_body
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
    NfeRequestTryListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/NfeRequestTryV1"
      required:
        - data
    NfeRequestTryPaginatedResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/NfeRequestTryV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    NfeExternalRequestSummaryV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        nfe_id:
          type:
            - string
            - "null"
          format: uuid
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
        direction:
          type: string
          enum:
            - outbound
            - inbound
          description: "Dirección de la solicitud: `outbound` (llamada saliente) o `inbound` (webhook recibido)."
        service:
          type:
            - string
            - "null"
          description: "Proveedor/servicio externo (ej.: `nfeio`, `barueri`)."
        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
        - nfe_id
        - invoice_id
        - direction
        - service
        - method
        - endpoint
        - http_status
        - success
        - error_message
        - duration_ms
        - created_at
    NfeExternalRequestV1:
      allOf:
        - $ref: "#/components/schemas/NfeExternalRequestSummaryV1"
        - type: object
          properties:
            request_headers:
              type:
                - object
                - "null"
              additionalProperties: {}
            request_body:
              type:
                - string
                - "null"
            response_headers:
              type:
                - object
                - "null"
              additionalProperties: {}
            response_body:
              type:
                - string
                - "null"
            metadata:
              type:
                - object
                - "null"
              additionalProperties: {}
          required:
            - request_headers
            - request_body
            - response_headers
            - response_body
            - metadata
    NfeExternalRequestListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/NfeExternalRequestSummaryV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    NfeExternalRequestResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/NfeExternalRequestV1"
      required:
        - data
    NfeFetchBarueriRequest:
      type: object
      properties:
        codigo_autenticidade:
          type: string
          minLength: 1
          description: Código de autenticidad impreso en el DANFSE de la NFS-e.
        cnpj_tomador:
          type: string
          minLength: 1
          description: CPF o CNPJ del tomador de la NFS-e (solo dígitos o con formato).
        ambiente:
          type: string
          enum:
            - production
            - homologation
          description: "Ambiente municipal: `production` o `homologation`. Por defecto: `production`."
      required:
        - codigo_autenticidade
        - cnpj_tomador
    NfeFetchBarueriResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    NfeImportBarueriRequest:
      type: object
      properties:
        xml:
          type: string
          description: XML crudo devuelto por `POST /nfes/fetch-barueri`. Opcional — cuando se omite, la NFS-e se vuelve a buscar con `codigo_autenticidade` + `cnpj_tomador`.
        codigo_autenticidade:
          type: string
          minLength: 1
          description: Código de autenticidad impreso en el DANFSE de la NFS-e.
        cnpj_tomador:
          type: string
          minLength: 1
          description: CPF o CNPJ del tomador de la NFS-e (solo dígitos o con formato).
        ambiente:
          type: string
          enum:
            - production
            - homologation
          description: "Ambiente municipal: `production` o `homologation`. Por defecto: `production`."
      required:
        - codigo_autenticidade
        - cnpj_tomador
    NfeImportBarueriResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    NfeValidateBarueriResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    NfeFetchFromSefazRequest:
      type: object
      properties:
        access_key:
          type: string
          minLength: 1
          description: Clave de acceso de la NFS-e (50 dígitos).
        certificate_id:
          type: string
          minLength: 1
          description: UUID del certificado digital registrado en la organización (usado para autenticación mTLS).
        ambiente:
          anyOf:
            - type: number
              enum:
                - 1
            - type: number
              enum:
                - 2
          description: "Ambiente SEFAZ: `1` (producción) o `2` (homologación). Por defecto: `2`."
      required:
        - access_key
        - certificate_id
    NfeFetchFromSefazResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    ProposalItemV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        proposal_id:
          type: string
          format: uuid
        product_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del producto.
        price_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del precio.
        quantity:
          type: number
          description: Cantidad.
        unit_amount:
          type: number
          description: Valor unitario en BRL (float, hasta 4 decimales).
        setup_amount:
          type:
            - number
            - "null"
          description: Setup unitario en BRL (float, hasta 4 decimales).
        excess_amount:
          type:
            - number
            - "null"
          description: Valor adicional por excedente en BRL (float, hasta 4 decimales).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - proposal_id
        - product_id
        - price_id
        - quantity
        - unit_amount
        - created_at
        - updated_at
    ProposalV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: UUID público — expuesto en URLs del portal (`/p/{code}`).
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora (opcional).
        code:
          type: string
          description: "Código corto único por organización (ej.: `PROP-0001`)."
        title:
          type: string
          description: 'Título de la propuesta (por defecto: "Proposta Comercial").'
        description:
          type:
            - string
            - "null"
          description: Descripción libre mostrada en la propuesta.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro destino, cuando la propuesta es para un cliente existente.
        prospect_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del prospect (persona jurídica en prospección), cuando aún no hay `billing_account_id`.
        contact_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del contacto (persona física responsable dentro del prospect).
        coupon_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del cupón aplicado a la propuesta.
        template_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del template usado para generar el PDF.
        document_google_id:
          type:
            - string
            - "null"
          description: ID del Google Doc generado por el App Script.
        document_url:
          type:
            - string
            - "null"
          description: URL del documento Google Doc.
        pdf_url:
          type:
            - string
            - "null"
          description: URL pública del PDF de la propuesta.
        generated_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de la última generación del PDF.
        pdf_outdated_at:
          type:
            - string
            - "null"
          format: date-time
          description: Marca cuándo el PDF quedó desactualizado respecto a los ítems/precios actuales.
        expires_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha de expiración de la propuesta.
        status:
          type: string
          enum:
            - draft
            - sent
            - viewed
            - accepted
            - rejected
            - expired
            - canceled
          description: "Estado: `draft`, `sent`, `viewed`, `accepted`, `rejected`, `expired` o `canceled`."
        rejection_reason:
          type:
            - string
            - "null"
          description: Motivo de rechazo informado por el prospect.
        discount_percent:
          type:
            - string
            - "null"
          description: 'Porcentaje de descuento negociado, decimal como string (ej.: `"10.00"` = 10%). Rango: 0–100. Aplicado sobre el valor mensual; el valor con descuento es la base de los ciclos y el descuento por ciclo se aplica encima, luego el cupón. Mutuamente excluyente con `discount_amount`.'
        discount_amount:
          type:
            - number
            - "null"
          description: "Descuento fijo negociado POR MES en BRL (float, hasta 4 decimales), aplicado sobre el valor mensual. El valor con descuento es la base de los ciclos; el descuento por ciclo se aplica encima. Mutuamente excluyente con `discount_percent`: al definir uno, el otro se borra. Al aceptar, el descuento combinado (propuesta + ciclo) se lleva a la suscripción."
          example: 50
        commitment_months:
          type:
            - integer
            - "null"
          description: "Permanencia: número de meses contratados. Copiado a la suscripción al aceptar; dentro de la ventana de permanencia el cliente no puede cancelar la suscripción por el portal."
          example: 12
        setup_amount:
          type: number
          description: Valor de setup (one-time) en BRL (float, hasta 4 decimales).
        monthly_amount:
          type: number
          description: Valor mensual recurrente en BRL (float, hasta 4 decimales).
        notes:
          type:
            - string
            - "null"
          description: Notas internas (no mostradas al cliente).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados definidos por la organización.
        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
        sent_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora del envío.
        viewed_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de la primera visualización por el destinatario.
        accepted_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora de la aceptación.
        rejected_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha y hora del rechazo.
        items:
          type: array
          items:
            $ref: "#/components/schemas/ProposalItemV1"
          description: Ítems de la propuesta — presente cuando se incluye vía `include=items`.
      required:
        - id
        - public_id
        - external_id
        - company_id
        - code
        - title
        - description
        - billing_account_id
        - prospect_id
        - contact_id
        - coupon_id
        - template_id
        - document_google_id
        - document_url
        - pdf_url
        - generated_at
        - pdf_outdated_at
        - expires_at
        - status
        - rejection_reason
        - discount_percent
        - discount_amount
        - commitment_months
        - setup_amount
        - monthly_amount
        - notes
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
        - sent_at
        - viewed_at
        - accepted_at
        - rejected_at
    ProposalListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProposalV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ProposalResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProposalV1"
      required:
        - data
    ProposalItemInput:
      type: object
      properties:
        product_id:
          type: string
          format: uuid
          description: UUID del producto. **Obligatorio**.
        price_id:
          type: string
          format: uuid
          description: UUID del precio. **Obligatorio**.
        quantity:
          type: number
          minimum: 1
          description: "Cantidad. Por defecto: 1."
        unit_amount:
          type: number
          minimum: 0
          description: Valor unitario en BRL (float, hasta 4 decimales).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados del ítem.
      required:
        - product_id
        - price_id
        - unit_amount
    ProspectDataInput:
      type: object
      properties:
        document:
          type: string
          description: CNPJ del prospect (solo dígitos o con formato).
        name:
          type: string
          minLength: 1
          description: Razón social del prospect.
        legal_name:
          type: string
          description: Razón social alternativa.
        nickname:
          type: string
          description: Nombre fantasía.
        email:
          type: string
          format: email
          description: Correo principal del prospect.
        phone:
          type: string
          description: Teléfono principal del prospect.
      required:
        - name
      description: Datos para crear un prospect inline (persona jurídica). Alternativa a `prospect_id`/`billing_account_id`.
    ContactDataInput:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre del contacto (persona responsable).
        email:
          type: string
          format: email
          description: Correo del contacto.
        phone:
          type: string
          description: Teléfono del contacto.
      required:
        - name
      description: Datos para crear un contacto inline (persona física responsable).
    ProposalCreateRequest:
      type: object
      properties:
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora. Usa `null` para limpiar.
        title:
          type: string
          minLength: 1
          maxLength: 255
          description: 'Título de la propuesta. Por defecto: "Proposta Comercial".'
        description:
          type:
            - string
            - "null"
          description: Descripción libre de la propuesta.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro destino (cliente existente). Obligatorio si no se informan `prospect_id` ni `prospect_data`.
        prospect_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de un prospect existente. Alternativa a `billing_account_id`/`prospect_data`.
        contact_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de un contacto existente vinculado al prospect.
        prospect_data:
          $ref: "#/components/schemas/ProspectDataInput"
        contact_data:
          $ref: "#/components/schemas/ContactDataInput"
        coupon_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del cupón a aplicar.
        template_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del template para generar el PDF.
        discount_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
          description: Porcentaje de descuento negociado (0–100), aplicado sobre el valor mensual; el descuento por ciclo se aplica sobre el valor con descuento. No lo envíe junto con `discount_amount`.
        discount_amount:
          type:
            - number
            - "null"
          minimum: 0
          description: Descuento fijo negociado por mes en BRL (float, hasta 4 decimales), aplicado sobre el valor mensual; el descuento por ciclo se aplica sobre el valor con descuento. No lo envíe junto con `discount_percent`.
          example: 50
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: Permanencia en meses (1–120). Use `null` para quitar. Copiado a la suscripción cuando se acepta la propuesta.
          example: 12
        expires_at:
          type: string
          description: Fecha de expiración.
        notes:
          type:
            - string
            - "null"
          description: Notas internas.
        items:
          type: array
          items:
            $ref: "#/components/schemas/ProposalItemInput"
          minItems: 1
          description: Ítems de la propuesta. Mínimo 1.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
    ProposalUpdateRequest:
      type: object
      properties:
        company_id:
          type:
            - string
            - "null"
          format: uuid
        title:
          type: string
          minLength: 1
          maxLength: 255
          description: Actualiza el título.
        description:
          type:
            - string
            - "null"
          description: Actualiza la descripción. Usa `null` para limpiar.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
        prospect_id:
          type:
            - string
            - "null"
          format: uuid
        contact_id:
          type:
            - string
            - "null"
          format: uuid
        prospect_data:
          $ref: "#/components/schemas/ProspectDataInput"
        contact_data:
          $ref: "#/components/schemas/ContactDataInput"
        coupon_id:
          type:
            - string
            - "null"
          format: uuid
        template_id:
          type:
            - string
            - "null"
          format: uuid
        discount_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
          description: Porcentaje de descuento negociado (0–100). Al definirlo, el valor fijo se borra. Usa `null` para limpiar el descuento. No lo envíe junto con `discount_amount`.
        discount_amount:
          type:
            - number
            - "null"
          minimum: 0
          description: Descuento fijo negociado por mes en BRL (float, hasta 4 decimales), aplicado sobre el valor mensual; el descuento por ciclo se aplica sobre el valor con descuento. Al definirlo, el porcentaje se borra. Usa `null` para limpiar. No lo envíe junto con `discount_percent`.
          example: 50
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: Permanencia en meses (1–120). Use `null` para quitar. Copiado a la suscripción cuando se acepta la propuesta.
          example: 12
        expires_at:
          type:
            - string
            - "null"
          description: Actualiza la fecha de expiración. Usa `null` para limpiar.
        notes:
          type:
            - string
            - "null"
          description: Actualiza las notas. Usa `null` para limpiar.
        items:
          type: array
          items:
            $ref: "#/components/schemas/ProposalItemInput"
          description: Sustituye la lista de ítems de la propuesta.
        external_id:
          type: string
          description: Nuevo identificador en su sistema externo.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    ProposalAcceptRequest:
      type: object
      properties:
        cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
          description: "Ciclo de cobro de la suscripción creada al aceptar: `monthly`, `quarterly`, `semiannual` o `annual`."
      required:
        - cycle
    ProposalAcceptResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            proposal:
              $ref: "#/components/schemas/ProposalV1"
            subscription_id:
              type:
                - string
                - "null"
              format: uuid
            invoice_id:
              type:
                - string
                - "null"
              format: uuid
          required:
            - proposal
            - subscription_id
            - invoice_id
      required:
        - data
    ProposalSendRequest:
      type: object
      properties:
        subject:
          type: string
          description: "Asunto personalizado del correo. Por defecto: `Proposta {code}`."
        message:
          type: string
          description: Mensaje HTML personalizado del cuerpo del correo.
    ProposalGeneratePdfResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            proposal:
              $ref: "#/components/schemas/ProposalV1"
            pdf:
              type: object
              properties:
                document_id:
                  type:
                    - string
                    - "null"
                document_url:
                  type:
                    - string
                    - "null"
                pdf_url:
                  type:
                    - string
                    - "null"
              required:
                - document_id
                - document_url
                - pdf_url
          required:
            - proposal
            - pdf
      required:
        - data
    ProposalJsonResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            template_data: {}
            proposal:
              type: object
              properties:
                id:
                  type: string
                  format: uuid
                code:
                  type: string
                template_google_doc_id:
                  type:
                    - string
                    - "null"
                document_google_id:
                  type:
                    - string
                    - "null"
              required:
                - id
                - code
                - template_google_doc_id
                - document_google_id
          required:
            - proposal
      required:
        - data
    ProposalPricingResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties: {}
      required:
        - data
    ProposalItemsListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProposalItemV1"
      required:
        - data
    ProposalItemResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProposalItemV1"
      required:
        - data
    ProposalItemUpdateRequest:
      type: object
      properties:
        quantity:
          type: integer
          minimum: 1
          description: Actualiza la cantidad.
        unit_amount:
          type: number
          minimum: 0
          description: Actualiza el valor unitario en BRL (float, hasta 4 decimales).
        setup_amount:
          type: number
          minimum: 0
          description: Actualiza el setup unitario en BRL (float, hasta 4 decimales).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: proposals.items.update.body.custom_metadata
    ProposalBulkRequest:
      type: object
      properties:
        ids:
          type: array
          items:
            type: string
            format: uuid
          minItems: 1
          maxItems: 100
          description: Lista de UUIDs de las propuestas objetivo. Mínimo 1, máximo 100.
      required:
        - ids
    ProposalBulkResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            success_count:
              type: integer
            failed_count:
              type: integer
            errors:
              type: array
              items:
                type: object
                additionalProperties: {}
          required:
            - success_count
            - failed_count
            - errors
      required:
        - data
    ProposalStatsResponse:
      type: object
      properties:
        data:
          type: object
          additionalProperties:
            type: integer
      required:
        - data
    ProposalDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    ProposalTemplateV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público estable de la plantilla.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        name:
          type: string
          description: Nombre de la plantilla (único por organización).
        description:
          type:
            - string
            - "null"
          description: Descripción libre de la plantilla.
        document_type:
          type: string
          enum:
            - google_doc
            - google_slides
          description: "Tipo de documento base: `google_doc` o `google_slides`."
        google_doc_id:
          type: string
          description: ID del Google Doc/Slides usado como base de la plantilla.
        app_script_url:
          type:
            - string
            - "null"
          description: URL del Apps Script que renderiza la plantilla, cuando esté configurado.
        google_drive_folder_id:
          type:
            - string
            - "null"
          description: ID de la carpeta de Google Drive donde se guardan las copias generadas.
        is_active:
          type: boolean
          description: Indica si la plantilla está disponible para usar en nuevas propuestas.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de la plantilla (estructura libre).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente para correlación interna.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - external_id
        - name
        - description
        - document_type
        - google_doc_id
        - app_script_url
        - google_drive_folder_id
        - is_active
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    ProposalTemplateListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ProposalTemplateV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ProposalTemplateResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProposalTemplateV1"
      required:
        - data
    ProposalTemplateCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre de la plantilla (único por organización).
        description:
          type:
            - string
            - "null"
          description: Descripción opcional de la plantilla.
        document_type:
          type: string
          enum:
            - google_doc
            - google_slides
          description: "Tipo de documento base: `google_doc` o `google_slides`. Por defecto: `google_doc`."
        google_doc_id:
          type: string
          minLength: 1
          description: ID del Google Doc/Slides usado como plantilla (único por organización).
        app_script_url:
          type:
            - string
            - "null"
          format: uri
          description: URL del Apps Script publicado que renderiza la plantilla, cuando aplique.
        google_drive_folder_id:
          type:
            - string
            - "null"
          description: ID de la carpeta de Google Drive donde se guardarán las copias generadas.
        is_active:
          type: boolean
          description: Cuando es `false`, crea la plantilla ya desactivada.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente para correlación interna.
      required:
        - name
        - google_doc_id
    ProposalTemplateUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nuevo nombre de la plantilla.
        description:
          type:
            - string
            - "null"
          description: Nueva descripción de la plantilla.
        document_type:
          type: string
          enum:
            - google_doc
            - google_slides
          description: "Nuevo tipo de documento base: `google_doc` o `google_slides`."
        google_doc_id:
          type: string
          minLength: 1
          description: Nuevo ID del Google Doc/Slides usado como plantilla.
        app_script_url:
          type:
            - string
            - "null"
          format: uri
          description: Nueva URL del Apps Script publicado.
        google_drive_folder_id:
          type:
            - string
            - "null"
          description: Nuevo ID de la carpeta de Google Drive.
        is_active:
          type: boolean
          description: Habilita o deshabilita la plantilla.
        external_id:
          type: string
          description: Nuevo identificador en su sistema externo.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Nuevos metadatos libres definidos por el cliente.
    PlanChangeV1:
      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 en su sistema externo, para idempotencia/sincronización.
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción objetivo del cambio.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización propietaria del recurso.
        from_plan_id:
          type: string
          format: uuid
          description: UUID del plan de origen.
        to_plan_id:
          type: string
          format: uuid
          description: UUID del plan de destino.
        change_type:
          type: string
          enum:
            - upgrade
            - downgrade
            - lateral
          description: "Tipo del cambio: `upgrade`, `downgrade` o `lateral`."
        status:
          type: string
          enum:
            - pending
            - scheduled
            - completed
            - canceled
            - failed
          description: "Estado: `pending`, `scheduled`, `completed`, `canceled` o `failed`."
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo se aplica/aplicó el cambio: `immediate` o `end_of_period`."
        proration_method:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo efectivamente usado.
        effective_date:
          type: string
          format: date-time
          description: Fecha en que el cambio entra en vigor.
        scheduled_date:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha agendada para aplicación (cuando `timing = end_of_period`).
        completed_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se completó el cambio.
        canceled_at:
          type:
            - string
            - "null"
          format: date-time
          description: Cuándo se canceló el cambio.
        from_price:
          type: number
          description: Precio del plan de origen en BRL (float, hasta 4 decimales).
          example: 100
        to_price:
          type: number
          description: Precio del plan de destino en BRL (float, hasta 4 decimales).
          example: 200
        price_difference:
          type: number
          description: Diferencia `to - from` en BRL (float, hasta 4 decimales).
        proration_credit:
          type: number
          description: Crédito generado por prorrateo en BRL (float, hasta 4 decimales).
        proration_charge:
          type: number
          description: Cargo adicional por prorrateo en BRL (float, hasta 4 decimales).
        days_remaining:
          type: integer
          description: Días restantes en el período actual al momento del cambio.
        total_days_in_period:
          type: integer
          description: Total de días en el período de cobro.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura de prorrateo emitida (si existe).
        credit_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del crédito generado (si existe).
        reason:
          type:
            - string
            - "null"
          description: Motivo registrado por el iniciador del cambio.
        initiated_by:
          type:
            - string
            - "null"
          description: Identificador del iniciador (email del usuario, nombre de la API key o `api`).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor). Completados por el motor de cambio de plan; no editables vía API.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - external_id
        - subscription_id
        - billing_account_id
        - organization_id
        - from_plan_id
        - to_plan_id
        - change_type
        - status
        - timing
        - proration_method
        - effective_date
        - scheduled_date
        - completed_at
        - canceled_at
        - from_price
        - to_price
        - price_difference
        - proration_credit
        - proration_charge
        - days_remaining
        - total_days_in_period
        - invoice_id
        - credit_id
        - reason
        - initiated_by
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    PlanChangeListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PlanChangeV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PlanChangeResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanChangeV1"
      required:
        - data
    PlanChangeExecuteRequest:
      type: object
      properties:
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción que tendrá su plan cambiado.
        to_plan_id:
          type: string
          format: uuid
          description: UUID del plan de destino.
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo aplicar el cambio: `immediate` (por defecto para upgrades) o `end_of_period` (por defecto para downgrades)."
        reason:
          type: string
          description: Motivo del cambio (registrado en el audit log).
      required:
        - subscription_id
        - to_plan_id
    PlanChangeExecuteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            plan_change_id:
              type: string
              format: uuid
              description: UUID del cambio de plan creado.
            invoice_id:
              type:
                - string
                - "null"
              format: uuid
              description: UUID de la factura de prorrateo emitida (si existe).
            credit_id:
              type:
                - string
                - "null"
              format: uuid
              description: UUID del crédito generado (si existe).
          required:
            - plan_change_id
            - invoice_id
            - credit_id
      required:
        - data
    PlanChangeStatsResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            total:
              type: integer
              description: Total de cambios en la ventana.
            by_type:
              type: object
              additionalProperties:
                type: integer
              description: "Conteo por tipo (claves: `upgrade`, `downgrade`, `lateral`)."
            by_status:
              type: object
              additionalProperties:
                type: integer
              description: Conteo por estado.
            upgrades:
              type: integer
              description: Cantidad de upgrades en la ventana.
            downgrades:
              type: integer
              description: Cantidad de downgrades en la ventana.
            total_proration_credits:
              type: number
              description: Suma de los créditos de prorrateo emitidos en BRL (float, hasta 4 decimales).
            total_proration_charges:
              type: number
              description: Suma de los cargos de prorrateo en BRL (float, hasta 4 decimales).
          required:
            - total
            - by_type
            - by_status
            - upgrades
            - downgrades
            - total_proration_credits
            - total_proration_charges
      required:
        - data
    PlanChangeConfigV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización propietaria de la configuración.
        allow_upgrade:
          type: boolean
          description: Los upgrades están habilitados.
        allow_downgrade:
          type: boolean
          description: Los downgrades están habilitados.
        upgrade_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto para upgrades.
        downgrade_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto para downgrades.
        upgrade_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Cuándo aplicar upgrades por defecto.
        downgrade_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Cuándo aplicar downgrades por defecto.
        refund_on_downgrade:
          type: boolean
          description: Reembolsa la diferencia al hacer downgrade.
        credit_on_downgrade:
          type: boolean
          description: Genera crédito al hacer downgrade.
        apply_discount_on_change:
          type: boolean
          description: Mantiene los descuentos activos al cambiar de plan.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - organization_id
        - allow_upgrade
        - allow_downgrade
        - upgrade_proration
        - downgrade_proration
        - upgrade_timing
        - downgrade_timing
        - refund_on_downgrade
        - credit_on_downgrade
        - apply_discount_on_change
        - created_at
        - updated_at
    PlanChangeConfigResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanChangeConfigV1"
      required:
        - data
    PlanChangeConfigUpdateRequest:
      type: object
      properties:
        allow_upgrade:
          type: boolean
          description: Habilita upgrades de plan para la organización.
        allow_downgrade:
          type: boolean
          description: Habilita downgrades de plan para la organización.
        upgrade_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Método de prorrateo por defecto para upgrades: `full_proration`, `no_proration` o `partial_proration`."
        downgrade_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto para downgrades.
        upgrade_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo aplicar upgrades: `immediate` o `end_of_period`."
        downgrade_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo aplicar downgrades: `immediate` o `end_of_period`."
        refund_on_downgrade:
          type: boolean
          description: Reembolsa la diferencia al hacer downgrade.
        credit_on_downgrade:
          type: boolean
          description: Genera crédito (en lugar de reembolso) al hacer downgrade.
        apply_discount_on_change:
          type: boolean
          description: Mantiene los descuentos activos al cambiar de plan.
    PlanChangeRuleV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        from_plan_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del plan de origen, o `null` para cualquiera.
        to_plan_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del plan de destino, o `null` para cualquiera.
        change_type:
          type:
            - string
            - "null"
          enum:
            - upgrade
            - downgrade
            - lateral
          description: "Tipo de cambio cubierto: `upgrade`, `downgrade` o `lateral` (o `null` para cualquiera)."
        allowed:
          type: boolean
          description: Cuando es `false`, la transición se bloquea.
        timing:
          type:
            - string
            - "null"
          enum:
            - immediate
            - end_of_period
          description: Timing sobrescrito por esta regla.
        proration_method:
          type:
            - string
            - "null"
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo sobrescrito por esta regla.
        discount_percent:
          type:
            - integer
            - "null"
          description: Descuento porcentual (0–100) aplicado.
        bonus_days:
          type:
            - integer
            - "null"
          description: Días bonus concedidos.
        message:
          type:
            - string
            - "null"
          description: Mensaje mostrado al cliente.
        is_active:
          type: boolean
          description: Si la regla está activa.
        priority:
          type: integer
          description: Prioridad para la resolución de conflictos (mayor gana).
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - from_plan_id
        - to_plan_id
        - change_type
        - allowed
        - timing
        - proration_method
        - discount_percent
        - bonus_days
        - message
        - is_active
        - priority
        - created_at
        - updated_at
    PlanChangeRuleListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PlanChangeRuleV1"
      required:
        - data
    PlanChangeRuleResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanChangeRuleV1"
      required:
        - data
    PlanChangeRuleCreateRequest:
      type: object
      properties:
        from_plan_id:
          type: string
          format: uuid
          description: UUID del plan de origen. Cuando se omite, la regla cubre cualquier plan de origen.
        to_plan_id:
          type: string
          format: uuid
          description: UUID del plan de destino. Cuando se omite, la regla cubre cualquier plan de destino.
        change_type:
          type: string
          enum:
            - upgrade
            - downgrade
            - lateral
          description: "Tipo de cambio: `upgrade`, `downgrade` o `lateral`."
        allowed:
          type: boolean
          description: Cuando es `false`, bloquea explícitamente la transición.
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Sobrescribe el timing del cambio: `immediate` o `end_of_period`."
        proration_method:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Sobrescribe el método de prorrateo: `full_proration`, `no_proration` o `partial_proration`."
        discount_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Descuento porcentual aplicado cuando esta regla coincide (0 a 100).
        bonus_days:
          type: integer
          minimum: 0
          description: Días bonus añadidos al período actual cuando se aplica esta regla.
        message:
          type: string
          description: "Mensaje libre mostrado en el portal/checkout (ej.: motivo del bloqueo)."
        priority:
          type: integer
          description: Prioridad para la resolución de conflictos cuando múltiples reglas coinciden (mayor gana).
    PlanChangeRuleUpdateRequest:
      type: object
      properties:
        allowed:
          type: boolean
          description: Cuando es `false`, bloquea explícitamente la transición.
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Sobrescribe el timing del cambio: `immediate` o `end_of_period`."
        proration_method:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Sobrescribe el método de prorrateo: `full_proration`, `no_proration` o `partial_proration`."
        discount_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Descuento porcentual aplicado cuando esta regla coincide (0 a 100).
        bonus_days:
          type: integer
          minimum: 0
          description: Días bonus añadidos al período actual cuando se aplica esta regla.
        message:
          type: string
          description: "Mensaje libre mostrado en el portal/checkout (ej.: motivo del bloqueo)."
        priority:
          type: integer
          description: Prioridad para la resolución de conflictos cuando múltiples reglas coinciden (mayor gana).
        is_active:
          type: boolean
          description: Desactiva la regla sin eliminarla.
    PlanChangeRuleDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    SubscriptionChangeConfigV1:
      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 dueña de la configuración.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        allow_item_add:
          type: boolean
          description: Si es `true`, permite agregar nuevos ítems a la suscripción.
        allow_item_remove:
          type: boolean
          description: Si es `true`, permite eliminar ítems de la suscripción.
        allow_quantity_change:
          type: boolean
          description: Si es `true`, permite cambiar la cantidad de ítems existentes.
        allow_price_swap:
          type: boolean
          description: Si es `true`, permite cambiar el precio (variante) de un ítem sin eliminarlo.
        add_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al agregar ítems.
        remove_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al eliminar ítems.
        quantity_up_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al aumentar cantidad.
        quantity_down_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al reducir cantidad.
        add_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al agregar ítems.
        remove_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al eliminar ítems.
        quantity_up_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al aumentar cantidad.
        quantity_down_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al reducir cantidad.
        refund_on_remove:
          type: boolean
          description: Si es `true`, emite reembolso al eliminar ítems. Requiere `creditOnRemove`.
        credit_on_remove:
          type: boolean
          description: Si es `true`, emite crédito para el cliente al eliminar ítems.
        portal_self_service:
          type: boolean
          description: Si es `true`, habilita el self-service del cliente desde el portal.
        portal_require_confirmation:
          type: boolean
          description: Si es `true`, exige confirmación explícita del cliente en el portal.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres asociados a la configuració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
      required:
        - id
        - public_id
        - organization_id
        - external_id
        - allow_item_add
        - allow_item_remove
        - allow_quantity_change
        - allow_price_swap
        - add_proration
        - remove_proration
        - quantity_up_proration
        - quantity_down_proration
        - add_timing
        - remove_timing
        - quantity_up_timing
        - quantity_down_timing
        - refund_on_remove
        - credit_on_remove
        - portal_self_service
        - portal_require_confirmation
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    SubscriptionChangeConfigResponse:
      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 dueña de la configuración.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        allow_item_add:
          type: boolean
          description: Si es `true`, permite agregar nuevos ítems a la suscripción.
        allow_item_remove:
          type: boolean
          description: Si es `true`, permite eliminar ítems de la suscripción.
        allow_quantity_change:
          type: boolean
          description: Si es `true`, permite cambiar la cantidad de ítems existentes.
        allow_price_swap:
          type: boolean
          description: Si es `true`, permite cambiar el precio (variante) de un ítem sin eliminarlo.
        add_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al agregar ítems.
        remove_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al eliminar ítems.
        quantity_up_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al aumentar cantidad.
        quantity_down_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo por defecto al reducir cantidad.
        add_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al agregar ítems.
        remove_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al eliminar ítems.
        quantity_up_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al aumentar cantidad.
        quantity_down_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: Momento de aplicación por defecto al reducir cantidad.
        refund_on_remove:
          type: boolean
          description: Si es `true`, emite reembolso al eliminar ítems. Requiere `creditOnRemove`.
        credit_on_remove:
          type: boolean
          description: Si es `true`, emite crédito para el cliente al eliminar ítems.
        portal_self_service:
          type: boolean
          description: Si es `true`, habilita el self-service del cliente desde el portal.
        portal_require_confirmation:
          type: boolean
          description: Si es `true`, exige confirmación explícita del cliente en el portal.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres asociados a la configuració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
      required:
        - id
        - public_id
        - organization_id
        - external_id
        - allow_item_add
        - allow_item_remove
        - allow_quantity_change
        - allow_price_swap
        - add_proration
        - remove_proration
        - quantity_up_proration
        - quantity_down_proration
        - add_timing
        - remove_timing
        - quantity_up_timing
        - quantity_down_timing
        - refund_on_remove
        - credit_on_remove
        - portal_self_service
        - portal_require_confirmation
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    SubscriptionChangeConfigUpdateRequest:
      type: object
      properties:
        allow_item_add:
          type: boolean
          description: Permite agregar nuevos ítems a una suscripción existente.
        allow_item_remove:
          type: boolean
          description: Permite eliminar ítems de una suscripción existente.
        allow_quantity_change:
          type: boolean
          description: Permite cambiar la cantidad de ítems ya presentes en la suscripción.
        allow_price_swap:
          type: boolean
          description: Permite cambiar el precio (variante) de un ítem existente sin eliminarlo.
        add_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Método de prorrateo al agregar ítems: `full_proration`, `no_proration` o `partial_proration`."
        remove_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Método de prorrateo al eliminar ítems: `full_proration`, `no_proration` o `partial_proration`."
        quantity_up_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo al aumentar la cantidad de un ítem.
        quantity_down_proration:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: Método de prorrateo al reducir la cantidad de un ítem.
        add_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Momento de aplicación al agregar ítems: `immediate` o `end_of_period`."
        remove_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Momento de aplicación al eliminar ítems: `immediate` o `end_of_period`."
        quantity_up_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Momento de aplicación al aumentar cantidad: `immediate` o `end_of_period`."
        quantity_down_timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Momento de aplicación al reducir cantidad: `immediate` o `end_of_period`."
        refund_on_remove:
          type: boolean
          description: Cuando es `true`, emite un reembolso al cliente al eliminar ítems. Requiere `credit_on_remove` habilitado.
        credit_on_remove:
          type: boolean
          description: Cuando es `true`, emite un crédito a favor del cliente al eliminar ítems.
        portal_self_service:
          type: boolean
          description: Cuando es `true`, permite que el cliente cambie su propia suscripción desde el portal.
        portal_require_confirmation:
          type: boolean
          description: Cuando es `true`, exige confirmación explícita del cliente antes de aplicar el cambio en el portal.
        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).
    SubscriptionItemChangeV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
          description: Identificador público (UUID) usado para integración externa.
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción objetivo del cambio.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro de la suscripción.
        external_id:
          type:
            - string
            - "null"
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        status:
          type: string
          enum:
            - pending
            - scheduled
            - completed
            - canceled
            - failed
          description: "Estado: `pending`, `scheduled`, `completed`, `canceled` o `failed`."
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Momento de aplicación: `immediate` o `end_of_period`."
        initiated_by_role:
          type: string
          description: "Origen del cambio: `dashboard`, `portal` o `api`."
        initiated_by:
          type:
            - string
            - "null"
          description: Identificador del usuario/integración que inició el cambio.
        proration_method:
          type: string
          enum:
            - full_proration
            - no_proration
            - partial_proration
          description: "Método de prorrateo efectivamente aplicado: `full_proration`, `no_proration` o `partial_proration`."
        proration_credit:
          type: number
          description: Crédito de prorrateo en BRL (float, hasta 4 decimales) emitido al cliente.
          example: 100
        proration_charge:
          type: number
          description: Cargo de prorrateo en BRL (float, hasta 4 decimales) emitido al cliente.
          example: 0
        days_remaining:
          type: integer
          description: Días restantes del período de cobro al momento de la aplicación.
        total_days_in_period:
          type: integer
          description: Total de días del período de cobro usado en el cálculo del prorrateo.
        changes:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: 'Snapshot del lote de operaciones aplicado. Cada entrada tiene la forma `{ op: "add"|"remove"|"update_qty"|"update_price", productId, priceId, quantity, prevQuantity?, prevPriceId?, prevUnitAmountSubcents?, unitAmountSubcents }`.'
        effective_date:
          type: string
          format: date-time
          description: Fecha efectiva del cambio (cuando entra en vigor).
        scheduled_date:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha agendada para la aplicación, cuando `timing = end_of_period`.
        completed_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora en que el cambio fue efectivamente aplicado.
        canceled_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora en que el cambio fue cancelado, cuando corresponde.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura generada por el cambio, cuando exista.
        credit_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del crédito generado por el cambio, cuando exista.
        reason:
          type:
            - string
            - "null"
          description: Motivo libre informado por el operador al registrar el cambio.
        idempotency_key:
          type:
            - string
            - "null"
          description: Clave de idempotencia por organización — permite reejecutar con seguridad.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente.
        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
      required:
        - id
        - public_id
        - subscription_id
        - billing_account_id
        - external_id
        - status
        - timing
        - initiated_by_role
        - initiated_by
        - proration_method
        - proration_credit
        - proration_charge
        - days_remaining
        - total_days_in_period
        - changes
        - effective_date
        - scheduled_date
        - completed_at
        - canceled_at
        - invoice_id
        - credit_id
        - reason
        - idempotency_key
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    SubscriptionItemChangeListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/SubscriptionItemChangeV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    SubscriptionItemChangeResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/SubscriptionItemChangeV1"
      required:
        - data
    UsageRecordV1:
      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 en su sistema externo, para idempotencia/sincronización.
        subscription_item_id:
          type: string
          format: uuid
          description: UUID del ítem de suscripción al que pertenece el uso.
        quantity:
          type: number
          description: Cantidad reportada en el registro.
          example: 5
        action:
          type: string
          enum:
            - increment
            - set
          description: "Tipo de acción: `increment` (suma) o `set` (reemplaza valores previos del período)."
        timestamp:
          type: string
          format: date-time
          description: Fecha/hora del uso (ISO 8601).
        idempotency_key:
          type:
            - string
            - "null"
          description: Clave de idempotencia usada al crear, si la hubo.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        created_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - external_id
        - subscription_item_id
        - quantity
        - action
        - timestamp
        - idempotency_key
        - metadata
        - custom_metadata
        - created_at
    UsageListMeta:
      type: object
      properties:
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
        total_quantity:
          type: number
        product_slug:
          type: string
        customer_id:
          type: string
      required:
        - total
        - limit
        - offset
        - total_quantity
    UsageListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/UsageRecordV1"
        meta:
          $ref: "#/components/schemas/UsageListMeta"
      required:
        - data
        - meta
    UsageRecordCreateInput:
      type: object
      properties:
        subscription_item_id:
          type: string
          format: uuid
          description: UUID del ítem de suscripción (opción 1 — alternativa a `product_slug` + `customer_id`).
        product_slug:
          type: string
          description: Slug del producto (opción 2). Combina con `customer_id` para ubicar la suscripción activa.
        customer_id:
          type: string
          description: Identificador externo del cliente (`external_id` del `billing_account`). Combina con `product_slug`.
        quantity:
          type: number
          minimum: 0
          description: "Cantidad a registrar — número no negativo. Ej.: `5`, `0`, `1500`."
          example: 5
        action:
          type: string
          enum:
            - increment
            - set
          description: "`increment` (por defecto) suma a la cantidad del período; `set` reemplaza cualquier valor previo del período hasta el momento."
        timestamp:
          type: string
          format: date-time
          description: "Fecha/hora del uso en ISO 8601. Por defecto: ahora."
        idempotency_key:
          type: string
          description: "Clave de idempotencia opcional. Si ya existe un registro con la misma clave para el ítem, devuelve el existente con `duplicate: true`."
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: usage.create.body.custom_metadata
      required:
        - quantity
    UsageRecordBatchCreateInput:
      type: object
      properties:
        records:
          type: array
          items:
            $ref: "#/components/schemas/UsageRecordCreateInput"
          minItems: 1
          maxItems: 100
          description: Lote de registros (1 a 100). Cuando está presente, procesa el lote e ignora el registro de nivel superior.
      required:
        - records
    UsageRecordCreateRequest:
      anyOf:
        - $ref: "#/components/schemas/UsageRecordCreateInput"
        - $ref: "#/components/schemas/UsageRecordBatchCreateInput"
    UsageRecordBatchResult:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del registro creado o ya existente.
        public_id:
          type: string
          format: uuid
          description: Identificador público estable del registro creado o ya existente.
        subscription_item_id:
          type: string
          format: uuid
        product_slug:
          type: string
        customer_id:
          type: string
        success:
          type: boolean
          description: Indica si el registro fue procesado con éxito.
        duplicate:
          type: boolean
          description: Cuando es `true`, indica que el registro ya existía con la misma `idempotency_key`.
        error:
          type: string
          description: Mensaje de error cuando `success` es `false`.
      required:
        - success
    UsageRecordCreateResponse:
      type: object
      properties:
        success:
          type: boolean
        processed:
          type: integer
        failed:
          type: integer
        partial:
          type: boolean
        results:
          anyOf:
            - $ref: "#/components/schemas/UsageRecordBatchResult"
            - type: array
              items:
                $ref: "#/components/schemas/UsageRecordBatchResult"
      required:
        - success
        - processed
        - results
    UsageSummaryProduct:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del producto asociado al ítem de suscripción.
        name:
          type: string
          description: Nombre del producto.
        slug:
          type: string
          description: Slug del producto.
      required:
        - id
        - name
        - slug
    UsageSummaryPeriod:
      type: object
      properties:
        start:
          type: string
          format: date-time
          description: Inicio del período usado por la agregación (ISO 8601).
        end:
          type: string
          format: date-time
          description: Fin del período usado por la agregación (ISO 8601).
      required:
        - start
        - end
    UsageSummaryUsage:
      type: object
      properties:
        total_quantity:
          type: number
          description: Cantidad total consolidada en el período.
        record_count:
          type: integer
          description: Número de registros considerados.
        first_record_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora del primer registro en el período (ISO 8601).
        last_record_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora del último registro en el período (ISO 8601).
      required:
        - total_quantity
        - record_count
        - first_record_at
        - last_record_at
    UsageSummaryBilling:
      type: object
      properties:
        estimated_cost:
          type:
            - number
            - "null"
          description: Costo estimado en BRL (float, hasta 4 decimales). `null` cuando el precio no permite el cálculo.
        price_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del precio usado para la estimación.
        usage_type:
          type:
            - string
            - "null"
          description: "Tipo de uso configurado en el precio (ej.: `metered`, `licensed`)."
      required:
        - estimated_cost
        - price_id
        - usage_type
    UsageSummaryResponse:
      type: object
      properties:
        subscription_item_id:
          type: string
          format: uuid
          description: UUID del ítem de suscripción al que pertenece el uso.
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción.
        subscription_status:
          type: string
          description: "Estado actual de la suscripción (ej.: `active`, `trialing`)."
        product:
          allOf:
            - $ref: "#/components/schemas/UsageSummaryProduct"
            - type:
                - object
                - "null"
        customer_id:
          type: string
        period:
          $ref: "#/components/schemas/UsageSummaryPeriod"
        usage:
          $ref: "#/components/schemas/UsageSummaryUsage"
        billing:
          $ref: "#/components/schemas/UsageSummaryBilling"
      required:
        - subscription_item_id
        - subscription_id
        - subscription_status
        - product
        - period
        - usage
        - billing
    UsageDailySnapshotV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización dueña del snapshot.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro asociada al snapshot.
        product_group_id:
          type: string
          format: uuid
          description: UUID del grupo de productos.
        product_id:
          type: string
          format: uuid
          description: UUID del producto.
        snapshot_date:
          type: string
          format: date-time
          description: Fecha del snapshot (ISO 8601, granularidad diaria).
        quantity:
          type: number
          description: Cantidad reportada en el registro.
        cumulative_quantity:
          type: number
          description: Cantidad acumulada del snapshot.
        idempotency_key:
          type: string
          description: Clave de idempotencia usada al crear, si la hubo.
        calculated_at:
          type: string
          format: date-time
          description: Fecha/hora en que el snapshot fue calculado (ISO 8601).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - organization_id
        - billing_account_id
        - product_group_id
        - product_id
        - snapshot_date
        - quantity
        - cumulative_quantity
        - idempotency_key
        - calculated_at
        - metadata
        - created_at
        - updated_at
    UsageSnapshotListMeta:
      type: object
      properties:
        total:
          type: integer
        limit:
          type: integer
        offset:
          type: integer
      required:
        - total
        - limit
        - offset
    UsageDailySnapshotListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/UsageDailySnapshotV1"
        meta:
          $ref: "#/components/schemas/UsageSnapshotListMeta"
      required:
        - data
        - meta
    UsageDailySnapshotCreateInput:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro. Alternativa a `billing_account_public_id`.
        billing_account_public_id:
          type: string
          description: Identificador público de la cuenta de cobro. Alternativa a `billing_account_id`.
        product_group_slug:
          type: string
          description: Slug del grupo de productos — obligatorio. Acota la búsqueda de `product_slug`/`product_id`.
        product_slug:
          type: string
          description: Slug del producto dentro del grupo. Alternativa a `product_id`.
        product_id:
          type: string
          format: uuid
          description: UUID del producto dentro del grupo. Alternativa a `product_slug`.
        snapshot_date:
          type: string
          description: Fecha del snapshot en formato `YYYY-MM-DD` (ISO 8601).
          example: 2026-03-15
        quantity:
          type: number
          minimum: 0
          description: Cantidad consolidada del día — número no negativo.
        cumulative_quantity:
          type: number
          minimum: 0
          description: "Cantidad acumulada hasta el día — número no negativo. Por defecto: 0."
        idempotency_key:
          type: string
          minLength: 1
          description: Clave de idempotencia **obligatoria**. Debe ser única entre snapshots.
        calculated_at:
          type: string
          format: date-time
          description: "Fecha/hora en que la cantidad fue calculada (ISO 8601). Por defecto: ahora."
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: usage.daily_snapshots.create.body.custom_metadata
      required:
        - product_group_slug
        - snapshot_date
        - quantity
        - idempotency_key
    UsageDailySnapshotBatchCreateInput:
      type: object
      properties:
        records:
          type: array
          items:
            $ref: "#/components/schemas/UsageDailySnapshotCreateInput"
          minItems: 1
          maxItems: 100
          description: Lote de snapshots diarios (1 a 100).
      required:
        - records
    UsageDailySnapshotCreateRequest:
      anyOf:
        - $ref: "#/components/schemas/UsageDailySnapshotCreateInput"
        - $ref: "#/components/schemas/UsageDailySnapshotBatchCreateInput"
    UsageDailySnapshotBatchResult:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del registro creado o ya existente.
        billing_account_id:
          type: string
          format: uuid
        product_id:
          type: string
          format: uuid
        success:
          type: boolean
          description: Indica si el registro fue procesado con éxito.
        overwritten:
          type: boolean
          description: Cuando es `true`, indica que un snapshot preexistente fue sobrescrito.
        error:
          type: string
          description: Mensaje de error cuando `success` es `false`.
        data:
          $ref: "#/components/schemas/UsageDailySnapshotV1"
      required:
        - success
    UsageDailySnapshotCreateResponse:
      type: object
      properties:
        success:
          type: boolean
        processed:
          type: integer
        failed:
          type: integer
        partial:
          type: boolean
        results:
          anyOf:
            - $ref: "#/components/schemas/UsageDailySnapshotBatchResult"
            - type: array
              items:
                $ref: "#/components/schemas/UsageDailySnapshotBatchResult"
      required:
        - success
        - processed
        - results
    UsageMonthlySnapshotV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización dueña del snapshot.
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro asociada al snapshot.
        product_group_id:
          type: string
          format: uuid
          description: UUID del grupo de productos.
        product_id:
          type: string
          format: uuid
          description: UUID del producto.
        month:
          type: string
          format: date-time
          description: Mes de referencia (ISO 8601 — primer día del mes).
        total_quantity:
          type: number
          description: Cantidad total acumulada del mes.
        cumulative_quantity:
          type: number
          description: Cantidad acumulada del snapshot.
        avg_daily_quantity:
          type: number
          description: Promedio diario de uso del mes.
        days_with_usage:
          type: integer
          description: Número de días con uso registrado en el mes.
        plan_limit:
          type:
            - number
            - "null"
          description: Límite contratado del plan para el período. `null` cuando es ilimitado.
        excess_quantity:
          type: number
          description: Cantidad excedente sobre el `plan_limit`.
        idempotency_key:
          type: string
          description: Clave de idempotencia usada al crear, si la hubo.
        calculated_at:
          type: string
          format: date-time
          description: Fecha/hora en que el snapshot fue calculado (ISO 8601).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - organization_id
        - billing_account_id
        - product_group_id
        - product_id
        - month
        - total_quantity
        - cumulative_quantity
        - avg_daily_quantity
        - days_with_usage
        - plan_limit
        - excess_quantity
        - idempotency_key
        - calculated_at
        - metadata
        - created_at
        - updated_at
    UsageMonthlySnapshotListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/UsageMonthlySnapshotV1"
        meta:
          $ref: "#/components/schemas/UsageSnapshotListMeta"
      required:
        - data
        - meta
    UsageMonthlySnapshotCreateInput:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro. Alternativa a `billing_account_public_id`.
        billing_account_public_id:
          type: string
          description: Identificador público de la cuenta de cobro. Alternativa a `billing_account_id`.
        product_group_slug:
          type: string
          description: Slug del grupo de productos — obligatorio.
        product_slug:
          type: string
          description: Slug del producto dentro del grupo. Alternativa a `product_id`.
        product_id:
          type: string
          format: uuid
          description: UUID del producto dentro del grupo. Alternativa a `product_slug`.
        month:
          type: string
          description: "Mes de referencia en formato `YYYY-MM-DD` (usa el primer día del mes, ej.: `2026-03-01`)."
          example: 2026-03-01
        total_quantity:
          type: number
          minimum: 0
          description: Cantidad total acumulada del mes — número no negativo.
        cumulative_quantity:
          type: number
          minimum: 0
          description: "Cantidad acumulada hasta el mes — número no negativo. Por defecto: 0."
        avg_daily_quantity:
          type: number
          minimum: 0
          description: Promedio diario de uso del mes — número no negativo.
        days_with_usage:
          type: integer
          minimum: 0
          description: Número de días con uso registrado (entero no negativo).
        plan_limit:
          type:
            - number
            - "null"
          description: Límite contratado del plan para el período (opcional). Usa `null` cuando es ilimitado.
        excess_quantity:
          type: number
          minimum: 0
          description: Cantidad excedente sobre el `plan_limit` — número no negativo.
        idempotency_key:
          type: string
          minLength: 1
          description: Clave de idempotencia **obligatoria**. Debe ser única entre snapshots.
        calculated_at:
          type: string
          format: date-time
          description: "Fecha/hora en que los números fueron calculados (ISO 8601). Por defecto: ahora."
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: usage.monthly_snapshots.create.body.custom_metadata
      required:
        - product_group_slug
        - month
        - total_quantity
        - avg_daily_quantity
        - days_with_usage
        - excess_quantity
        - idempotency_key
    UsageMonthlySnapshotBatchCreateInput:
      type: object
      properties:
        records:
          type: array
          items:
            $ref: "#/components/schemas/UsageMonthlySnapshotCreateInput"
          minItems: 1
          maxItems: 100
          description: Lote de snapshots mensuales (1 a 100).
      required:
        - records
    UsageMonthlySnapshotCreateRequest:
      anyOf:
        - $ref: "#/components/schemas/UsageMonthlySnapshotCreateInput"
        - $ref: "#/components/schemas/UsageMonthlySnapshotBatchCreateInput"
    UsageMonthlySnapshotBatchResult:
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: UUID del registro creado o ya existente.
        billing_account_id:
          type: string
          format: uuid
        product_id:
          type: string
          format: uuid
        success:
          type: boolean
          description: Indica si el registro fue procesado con éxito.
        overwritten:
          type: boolean
          description: Cuando es `true`, indica que un snapshot preexistente fue sobrescrito.
        error:
          type: string
          description: Mensaje de error cuando `success` es `false`.
        data:
          $ref: "#/components/schemas/UsageMonthlySnapshotV1"
      required:
        - success
    UsageMonthlySnapshotCreateResponse:
      type: object
      properties:
        success:
          type: boolean
        processed:
          type: integer
        failed:
          type: integer
        partial:
          type: boolean
        results:
          anyOf:
            - $ref: "#/components/schemas/UsageMonthlySnapshotBatchResult"
            - type: array
              items:
                $ref: "#/components/schemas/UsageMonthlySnapshotBatchResult"
      required:
        - success
        - processed
        - results
    TaxRuleItemV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tax_rule_id:
          type: string
          format: uuid
          description: UUID de la regla a la que pertenece el ítem.
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - inss
            - cbs
            - ibs
          description: "Tributo: `iss`, `pis`, `cofins`, `csll`, `irpj`, `irrf`, `csrf`, `inss`, `cbs` o `ibs`."
        rate:
          type: number
          description: "Alícuota porcentual (0–100), hasta 2 decimales. Ej.: `5.00` = 5%."
          example: 5
        is_withheld:
          type: boolean
          description: Cuando es `true`, el tributo es retenido en la fuente.
        base_type:
          type: string
          enum:
            - service_value
            - service_value_minus_iss
            - presumed_base
          description: "Base de cálculo: `service_value`, `service_value_minus_iss` o `presumed_base`."
        is_exempt:
          type: boolean
          description: Cuando es `true`, indica exención del tributo.
        exemption_reason:
          type:
            - string
            - "null"
          description: Justificación de la exención, cuando `is_exempt = true`.
        created_at:
          type: string
          format: date-time
      required:
        - id
        - tax_rule_id
        - tax_type
        - rate
        - is_withheld
        - base_type
        - is_exempt
        - exemption_reason
        - created_at
    TaxRuleV1:
      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 en su sistema externo, para idempotencia/sincronización.
        scope:
          type: string
          enum:
            - global
            - organization
            - company
            - service
            - customer
            - municipality
          description: "Alcance de la regla: `global`, `organization`, `company`, `service`, `customer` o `municipality`."
        priority:
          type: integer
          description: Prioridad. Mayor valor sobrescribe reglas de menor prioridad.
          example: 0
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa cuando `scope = company`.
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del ítem de servicio cuando `scope = service`.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro cuando `scope = customer`.
        customer_tax_type:
          type:
            - string
            - "null"
          enum:
            - pessoa_fisica
            - pessoa_juridica
            - mei
            - simples_optante
            - entidade_publica
          description: Tipo tributario del cliente que la regla cubre.
        municipality:
          type:
            - string
            - "null"
          description: Código IBGE del municipio (7 dígitos) cuando `scope = municipality`.
        operation_type:
          type:
            - string
            - "null"
          enum:
            - interno
            - externo
          description: "Tipo de operación: `interno` o `externo`."
        name:
          type: string
          description: Nombre legible de la regla.
        description:
          type:
            - string
            - "null"
          description: Descripción de la regla.
        is_active:
          type: boolean
          description: Indica si la regla está activa.
        effective_from:
          type: string
          format: date-time
          description: Fecha/hora ISO 8601 a partir de la cual la regla rige.
        effective_to:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora ISO 8601 en que la regla deja de regir. `null` significa vigencia indeterminada.
        items:
          type: array
          items:
            $ref: "#/components/schemas/TaxRuleItemV1"
          description: Lista de ítems de la regla — una entrada por tributo.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        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
      required:
        - id
        - public_id
        - external_id
        - scope
        - priority
        - company_id
        - service_item_id
        - billing_account_id
        - customer_tax_type
        - municipality
        - operation_type
        - name
        - description
        - is_active
        - effective_from
        - effective_to
        - items
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    TaxRuleListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TaxRuleV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    TaxRuleResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/TaxRuleV1"
      required:
        - data
    TaxRuleItemInput:
      type: object
      properties:
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - inss
            - cbs
            - ibs
          description: "Tributo: `iss`, `pis`, `cofins`, `csll`, `irpj`, `irrf`, `csrf`, `inss`, `cbs` o `ibs`."
        rate:
          type: number
          minimum: 0
          maximum: 100
          description: "Alícuota porcentual (0–100), hasta 2 decimales. Ej.: `5.00` = 5%."
          example: 5
        is_withheld:
          type: boolean
          description: Cuando es `true`, el tributo es retenido en la fuente.
        base_type:
          type: string
          enum:
            - service_value
            - service_value_minus_iss
            - presumed_base
          description: "Base de cálculo: `service_value`, `service_value_minus_iss` o `presumed_base`."
        is_exempt:
          type: boolean
          description: Cuando es `true`, indica exención del tributo.
        exemption_reason:
          type:
            - string
            - "null"
          description: Justificación de la exención, cuando `is_exempt = true`.
      required:
        - tax_type
        - rate
    TaxRuleCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre legible de la regla.
        description:
          type:
            - string
            - "null"
          description: Descripción opcional de la regla.
        scope:
          type: string
          enum:
            - global
            - organization
            - company
            - service
            - customer
            - municipality
          description: "Alcance de la regla: `global`, `organization`, `company`, `service`, `customer` o `municipality`."
        priority:
          type: integer
          description: "Prioridad de la regla. Mayor valor sobrescribe reglas de menor prioridad. Por defecto: `0`."
          example: 0
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa cuando `scope = company`. La empresa debe pertenecer a la organización actual.
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del ítem de servicio cuando `scope = service`. El ítem debe pertenecer a la organización actual.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro cuando `scope = customer`. La cuenta debe pertenecer a la organización actual.
        customer_tax_type:
          type:
            - string
            - "null"
          enum:
            - pessoa_fisica
            - pessoa_juridica
            - mei
            - simples_optante
            - entidade_publica
          description: "Tipo tributario del cliente: `pessoa_fisica`, `pessoa_juridica`, `mei`, `simples_optante` o `entidade_publica`."
        municipality:
          type:
            - string
            - "null"
          description: Código IBGE del municipio (7 dígitos) cuando `scope = municipality`.
        operation_type:
          type:
            - string
            - "null"
          enum:
            - interno
            - externo
          description: "Tipo de operación: `interno` (mismo municipio) o `externo` (municipio diferente)."
        effective_from:
          type: string
          format: date-time
          description: Fecha/hora ISO 8601 en que la regla entra en vigor.
        effective_to:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora ISO 8601 en que la regla deja de regir. `null` significa vigencia indeterminada.
        items:
          type: array
          items:
            $ref: "#/components/schemas/TaxRuleItemInput"
          minItems: 1
          description: Lista de ítems (alícuotas por tributo). Se requiere al menos 1 ítem.
        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
        - scope
        - items
    TaxRuleUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nuevo nombre de la regla.
        description:
          type:
            - string
            - "null"
          description: Nueva descripción de la regla.
        priority:
          type: integer
          description: Nueva prioridad de la regla.
        is_active:
          type: boolean
          description: Cuando es `false`, desactiva la regla sin eliminarla.
        effective_to:
          type:
            - string
            - "null"
          format: date-time
          description: Nueva fecha/hora ISO 8601 de fin de vigencia (o `null` para indeterminada).
        items:
          type: array
          items:
            $ref: "#/components/schemas/TaxRuleItemInput"
          description: Cuando se informa, reemplaza por completo la lista de ítems de la regla.
        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).
    TaxRuleDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    LateFeePolicyV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        name:
          type: string
          description: Nombre de la política, único en la organización.
          example: Padrão
        is_default:
          type: boolean
          description: Indica si es la política por defecto de la organización.
        fine_mode:
          type: string
          enum:
            - none
            - percentage
            - fixed
          description: Cómo se calcula la multa. Se cobra una sola vez. `percentage` usa `fine_percent`, `fixed` usa `fine_amount`.
        fine_percent:
          type:
            - number
            - "null"
          description: Porcentaje de la multa sobre el saldo, de 0 a 100. Solo se completa cuando `fine_mode` es `percentage`.
          example: 2
        fine_amount:
          type:
            - number
            - "null"
          description: Valor fijo de la multa, en reales. Solo se completa cuando `fine_mode` es `fixed`.
          example: 50
        fine_days:
          type: integer
          description: Días después del vencimiento en que la multa comienza a aplicarse. El valor por defecto es 1 — el día siguiente al vencimiento.
          example: 1
        interest_mode:
          type: string
          enum:
            - none
            - daily_amount
            - daily_percentage
            - monthly_percentage
            - yearly_percentage
          description: Cómo corren los intereses. Los modos porcentuales usan `interest_percent`; `daily_amount` usa `interest_amount`. Los intereses se cobran solo sobre el principal, nunca sobre principal más multa.
        interest_percent:
          type:
            - number
            - "null"
          description: Porcentaje de intereses por día, mes o año, según `interest_mode`. La tasa mensual se divide pro rata die por 30; la anual, por 360.
          example: 1
        interest_amount:
          type:
            - number
            - "null"
          description: Valor fijo de intereses por día, en reales. Solo se completa cuando `interest_mode` es `daily_amount`.
          example: 1.5
        interest_days:
          type: integer
          description: Días después del vencimiento en que los intereses comienzan a correr. El valor por defecto es 1.
          example: 1
        day_count:
          type: string
          enum:
            - calendar
            - business
          description: "Base de conteo de los días de atraso. Por ahora solo se acepta `calendar`: el cálculo local aún no tiene calendario de feriados, y contar días hábiles sin él sobrestimaría el cargo frente a lo que recauda el banco."
        max_interest_months:
          type:
            - integer
            - "null"
          description: Límite de meses de intereses acumulados. Nulo significa sin límite.
        max_total_charge_percent:
          type:
            - number
            - "null"
          description: Límite del cargo total (multa más intereses) como porcentaje del saldo. La multa se preserva y los intereses se recortan cuando el tope actúa.
        enforce_legal_caps:
          type: boolean
          description: Cuando es verdadero, rechaza multa superior al 2% e intereses superiores al 1% mensual. Desactivarlo es una decisión deliberada para contratos fuera de la relación de consumo, y se audita.
        partial_allocation:
          type: string
          enum:
            - charges_first
            - principal_first
          description: "Orden de imputación cuando un pago no cubre principal y cargos. `charges_first` sigue el art. 354 del Código Civil brasileño: intereses antes del capital."
        register_on_charge:
          type: boolean
          description: Registra la instrucción de multa e intereses en el banco al emitir boleto o Pix, para que el propio cobro recaude los cargos después del vencimiento.
        apply_on_dynamic_charge:
          type: boolean
          description: Recalcula el valor cobrado en tarjeta y en reemisiones, donde no existe instrucción bancaria que cobre el cargo.
        charge_instructions:
          type:
            - string
            - "null"
          description: Texto libre impreso en las instrucciones del boleto.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - name
        - is_default
        - fine_mode
        - fine_percent
        - fine_amount
        - fine_days
        - interest_mode
        - interest_percent
        - interest_amount
        - interest_days
        - day_count
        - max_interest_months
        - max_total_charge_percent
        - enforce_legal_caps
        - partial_allocation
        - register_on_charge
        - apply_on_dynamic_charge
        - charge_instructions
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    LateFeePolicyListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/LateFeePolicyV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    LateFeePolicyResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/LateFeePolicyV1"
      required:
        - data
    LateFeePolicyCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
          description: Nombre de la política, único en la organización.
          example: Padrão
        is_default:
          type: boolean
          description: Indica si es la política por defecto de la organización.
        fine_mode:
          type: string
          enum:
            - none
            - percentage
            - fixed
          description: Cómo se calcula la multa. Se cobra una sola vez. `percentage` usa `fine_percent`, `fixed` usa `fine_amount`.
        fine_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Porcentaje de la multa sobre el saldo, de 0 a 100. Solo se completa cuando `fine_mode` es `percentage`.
          example: 2
        fine_amount:
          type: number
          minimum: 0
          description: Valor fijo de la multa, en reales. Solo se completa cuando `fine_mode` es `fixed`.
        fine_days:
          type: integer
          minimum: 0
          maximum: 365
          description: Días después del vencimiento en que la multa comienza a aplicarse. El valor por defecto es 1 — el día siguiente al vencimiento.
        interest_mode:
          type: string
          enum:
            - none
            - daily_amount
            - daily_percentage
            - monthly_percentage
            - yearly_percentage
          description: Cómo corren los intereses. Los modos porcentuales usan `interest_percent`; `daily_amount` usa `interest_amount`. Los intereses se cobran solo sobre el principal, nunca sobre principal más multa.
        interest_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Porcentaje de intereses por día, mes o año, según `interest_mode`. La tasa mensual se divide pro rata die por 30; la anual, por 360.
          example: 1
        interest_amount:
          type: number
          minimum: 0
          description: Valor fijo de intereses por día, en reales. Solo se completa cuando `interest_mode` es `daily_amount`.
        interest_days:
          type: integer
          minimum: 0
          maximum: 365
          description: Días después del vencimiento en que los intereses comienzan a correr. El valor por defecto es 1.
        day_count:
          type: string
          enum:
            - calendar
            - business
          description: "Base de conteo de los días de atraso. Por ahora solo se acepta `calendar`: el cálculo local aún no tiene calendario de feriados, y contar días hábiles sin él sobrestimaría el cargo frente a lo que recauda el banco."
        max_interest_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: Límite de meses de intereses acumulados. Nulo significa sin límite.
        max_total_charge_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
          description: Límite del cargo total (multa más intereses) como porcentaje del saldo. La multa se preserva y los intereses se recortan cuando el tope actúa.
        enforce_legal_caps:
          type: boolean
          description: Cuando es verdadero, rechaza multa superior al 2% e intereses superiores al 1% mensual. Desactivarlo es una decisión deliberada para contratos fuera de la relación de consumo, y se audita.
        partial_allocation:
          type: string
          enum:
            - charges_first
            - principal_first
          description: "Orden de imputación cuando un pago no cubre principal y cargos. `charges_first` sigue el art. 354 del Código Civil brasileño: intereses antes del capital."
        register_on_charge:
          type: boolean
          description: Registra la instrucción de multa e intereses en el banco al emitir boleto o Pix, para que el propio cobro recaude los cargos después del vencimiento.
        apply_on_dynamic_charge:
          type: boolean
          description: Recalcula el valor cobrado en tarjeta y en reemisiones, donde no existe instrucción bancaria que cobre el cargo.
        charge_instructions:
          type:
            - string
            - "null"
          maxLength: 500
          description: Texto libre impreso en las instrucciones del boleto.
      required:
        - name
    LateFeePolicyUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 120
          description: Nombre de la política, único en la organización.
        is_default:
          type: boolean
          description: Indica si es la política por defecto de la organización.
        fine_mode:
          type: string
          enum:
            - none
            - percentage
            - fixed
          description: Cómo se calcula la multa. Se cobra una sola vez. `percentage` usa `fine_percent`, `fixed` usa `fine_amount`.
        fine_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Porcentaje de la multa sobre el saldo, de 0 a 100. Solo se completa cuando `fine_mode` es `percentage`.
          example: 2
        fine_amount:
          type: number
          minimum: 0
          description: Valor fijo de la multa, en reales. Solo se completa cuando `fine_mode` es `fixed`.
        fine_days:
          type: integer
          minimum: 0
          maximum: 365
          description: Días después del vencimiento en que la multa comienza a aplicarse. El valor por defecto es 1 — el día siguiente al vencimiento.
        interest_mode:
          type: string
          enum:
            - none
            - daily_amount
            - daily_percentage
            - monthly_percentage
            - yearly_percentage
          description: Cómo corren los intereses. Los modos porcentuales usan `interest_percent`; `daily_amount` usa `interest_amount`. Los intereses se cobran solo sobre el principal, nunca sobre principal más multa.
        interest_percent:
          type: number
          minimum: 0
          maximum: 100
          description: Porcentaje de intereses por día, mes o año, según `interest_mode`. La tasa mensual se divide pro rata die por 30; la anual, por 360.
          example: 1
        interest_amount:
          type: number
          minimum: 0
          description: Valor fijo de intereses por día, en reales. Solo se completa cuando `interest_mode` es `daily_amount`.
        interest_days:
          type: integer
          minimum: 0
          maximum: 365
          description: Días después del vencimiento en que los intereses comienzan a correr. El valor por defecto es 1.
        day_count:
          type: string
          enum:
            - calendar
            - business
          description: "Base de conteo de los días de atraso. Por ahora solo se acepta `calendar`: el cálculo local aún no tiene calendario de feriados, y contar días hábiles sin él sobrestimaría el cargo frente a lo que recauda el banco."
        max_interest_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: Límite de meses de intereses acumulados. Nulo significa sin límite.
        max_total_charge_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
          description: Límite del cargo total (multa más intereses) como porcentaje del saldo. La multa se preserva y los intereses se recortan cuando el tope actúa.
        enforce_legal_caps:
          type: boolean
          description: Cuando es verdadero, rechaza multa superior al 2% e intereses superiores al 1% mensual. Desactivarlo es una decisión deliberada para contratos fuera de la relación de consumo, y se audita.
        partial_allocation:
          type: string
          enum:
            - charges_first
            - principal_first
          description: "Orden de imputación cuando un pago no cubre principal y cargos. `charges_first` sigue el art. 354 del Código Civil brasileño: intereses antes del capital."
        register_on_charge:
          type: boolean
          description: Registra la instrucción de multa e intereses en el banco al emitir boleto o Pix, para que el propio cobro recaude los cargos después del vencimiento.
        apply_on_dynamic_charge:
          type: boolean
          description: Recalcula el valor cobrado en tarjeta y en reemisiones, donde no existe instrucción bancaria que cobre el cargo.
        charge_instructions:
          type:
            - string
            - "null"
          maxLength: 500
          description: Texto libre impreso en las instrucciones del boleto.
    LateFeePolicyDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
          required:
            - deleted
      required:
        - data
    LateChargesSimulateRequest:
      type: object
      properties:
        principal:
          type: number
          exclusiveMinimum: 0
          description: Saldo sobre el cual calcular los cargos, en reales.
          example: 1000
        due_date:
          type: string
          format: date-time
          description: Vencimiento a partir del cual se cuenta el atraso.
        reference_date:
          type: string
          format: date-time
          description: Fecha de cálculo. Por defecto, ahora. Los días se cuentan en la fecha civil en America/Sao_Paulo.
        policy_id:
          type: string
          format: uuid
          description: Política existente a usar. Alternativa a `policy`.
        policy:
          allOf:
            - $ref: "#/components/schemas/LateFeePolicyUpdateRequest"
            - description: Política inline, con los mismos campos que en la creación. Alternativa a `policy_id`.
      required:
        - principal
        - due_date
    LateChargesSimulateResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            days_past_due:
              type: integer
              description: Días corridos después del vencimiento.
            interest_days_elapsed:
              type: integer
              description: Días en que los intereses efectivamente corrieron, ya descontado `interest_days` y cualquier tope.
            fine:
              type: number
              description: Multa devengada, en reales.
              example: 20
            interest:
              type: number
              description: Intereses devengados, en reales.
              example: 10
            total:
              type: number
              description: Suma de multa e intereses, en reales.
              example: 30
            principal:
              type: number
              description: Saldo sobre el cual calcular los cargos, en reales.
              example: 1000
            total_due:
              type: number
              description: Saldo más los cargos.
              example: 1030
            capped_by:
              type:
                - string
                - "null"
              enum:
                - max_interest_months
                - max_total_charge
              description: Qué tope recortó el resultado, si alguno lo hizo.
            as_of:
              type: string
              format: date-time
              description: Fecha de cálculo usada. Los cargos cambian cada día, por eso el resultado no se persiste.
          required:
            - days_past_due
            - interest_days_elapsed
            - fine
            - interest
            - total
            - principal
            - total_due
            - capped_by
            - as_of
      required:
        - data
    HolidayV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        date:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: "Día civil del feriado, en formato `YYYY-MM-DD`. Sin hora: un feriado es una fecha del calendario, y aceptar un instante haría que el día guardado dependiera de la zona horaria del emisor."
          example: 2026-01-01
        name:
          type: string
          description: Nombre del feriado. Junto con la fecha identifica la fila — un feriado municipal y uno nacional pueden caer el mismo día.
          example: Confraternização mundial
        type:
          type: string
          enum:
            - national
            - state
            - municipal
            - optional
            - custom
          description: "Alcance: nacional, estatal, municipal, punto facultativo (`optional`) o propio de la organización (`custom`)."
        source:
          type: string
          enum:
            - brasil_api
            - manual
          description: "De dónde vino la fila: `brasil_api` para lo que trajo la importación, `manual` para lo ingresado. La importación actualiza lo que ella trajo y no toca lo digitado."
        notes:
          type:
            - string
            - "null"
          description: Texto libre — la ciudad de un feriado municipal, o cualquier observación.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
        - id
        - public_id
        - date
        - name
        - type
        - source
        - notes
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    HolidayListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/HolidayV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    HolidayResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/HolidayV1"
      required:
        - data
    HolidayCreateRequest:
      type: object
      properties:
        date:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: "Día civil del feriado, en formato `YYYY-MM-DD`. Sin hora: un feriado es una fecha del calendario, y aceptar un instante haría que el día guardado dependiera de la zona horaria del emisor."
          example: 2026-07-09
        name:
          type: string
          minLength: 1
          maxLength: 120
          description: Nombre del feriado. Junto con la fecha identifica la fila — un feriado municipal y uno nacional pueden caer el mismo día.
          example: Revolução Constitucionalista
        type:
          type: string
          enum:
            - national
            - state
            - municipal
            - optional
            - custom
          description: "Alcance: nacional, estatal, municipal, punto facultativo (`optional`) o propio de la organización (`custom`)."
        notes:
          type:
            - string
            - "null"
          maxLength: 500
          description: Texto libre — la ciudad de un feriado municipal, o cualquier observación.
      required:
        - date
        - name
    HolidayUpdateRequest:
      type: object
      properties:
        date:
          type: string
          pattern: ^\d{4}-\d{2}-\d{2}$
          description: "Día civil del feriado, en formato `YYYY-MM-DD`. Sin hora: un feriado es una fecha del calendario, y aceptar un instante haría que el día guardado dependiera de la zona horaria del emisor."
        name:
          type: string
          minLength: 1
          maxLength: 120
          description: Nombre del feriado. Junto con la fecha identifica la fila — un feriado municipal y uno nacional pueden caer el mismo día.
        type:
          type: string
          enum:
            - national
            - state
            - municipal
            - optional
            - custom
          description: "Alcance: nacional, estatal, municipal, punto facultativo (`optional`) o propio de la organización (`custom`)."
        notes:
          type:
            - string
            - "null"
          maxLength: 500
          description: Texto libre — la ciudad de un feriado municipal, o cualquier observación.
    HolidayDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
          required:
            - deleted
      required:
        - data
    HolidaySyncRequest:
      type: object
      properties:
        years:
          type: array
          items:
            type: integer
            minimum: 1900
            maximum: 2199
          minItems: 1
          maxItems: 20
          description: Años a importar. Por omisión, el año corriente y los dos siguientes.
          example:
            - 2026
            - 2027
    HolidaySyncResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            years:
              type: array
              items:
                type: integer
              description: Años procesados.
            created:
              type: integer
              description: Feriados insertados.
            existing:
              type: integer
              description: Ya presentes — nada que hacer.
            skipped_removed:
              type: integer
              description: Presentes pero eliminados, por lo tanto dejados fuera a propósito.
          required:
            - years
            - created
            - existing
            - skipped_removed
      required:
        - data
    BankV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        code:
          type: string
          description: Código COMPE de 3 dígitos.
          example: "341"
        name:
          type: string
          description: Nombre del banco.
          example: Itaú Unibanco S.A.
      required:
        - id
        - code
        - name
    BankListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BankV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    BankAccountV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        external_id:
          type:
            - string
            - "null"
          description: Identificador en el sistema de origen (reservado a la integración con Financeiro Inteligente).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        bank_id:
          type: string
          format: uuid
          description: UUID del banco (vea `/banks`).
        name:
          type: string
          description: Alias de la cuenta, para el operador.
          example: Conta principal Itaú
        type:
          type: string
          enum:
            - checking
            - savings
          description: "`checking` (corriente) o `savings` (ahorro)."
        agency:
          type: string
          description: Agencia, solo dígitos.
          example: "1234"
        agency_digit:
          type:
            - string
            - "null"
          description: Dígito de la agencia, cuando lo haya.
        account_number:
          type: string
          description: Número de cuenta, solo dígitos.
          example: "56789"
        account_digit:
          type:
            - string
            - "null"
          description: Dígito de la cuenta, cuando lo haya.
          example: "0"
        holder_name:
          type:
            - string
            - "null"
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
          example: "12345678000190"
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        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_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_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
        bank:
          allOf:
            - $ref: "#/components/schemas/BankV1"
            - type:
                - object
                - "null"
              description: El banco de la cuenta.
      required:
        - id
        - public_id
        - external_id
        - company_id
        - bank_id
        - name
        - type
        - agency
        - agency_digit
        - account_number
        - account_digit
        - holder_name
        - holder_document
        - active
        - metadata
        - custom_metadata
        - created_via
        - created_by_email
        - updated_via
        - updated_by_email
        - created_at
        - updated_at
        - bank
    BankAccountListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/BankAccountV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    BankAccountResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/BankAccountV1"
      required:
        - data
    BankAccountCreateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Alias de la cuenta, para el operador.
          example: Conta principal Itaú
        bank_id:
          type: string
          format: uuid
          description: UUID del banco (vea `/banks`).
        type:
          type: string
          enum:
            - checking
            - savings
          description: "`checking` (corriente) o `savings` (ahorro)."
        agency:
          type: string
          minLength: 1
          maxLength: 50
          description: Agencia, solo dígitos.
          example: "1234"
        agency_digit:
          type:
            - string
            - "null"
          maxLength: 5
          description: Dígito de la agencia, cuando lo haya.
        account_number:
          type: string
          minLength: 1
          maxLength: 50
          description: Número de cuenta, solo dígitos.
          example: "56789"
        account_digit:
          type:
            - string
            - "null"
          maxLength: 5
          description: Dígito de la cuenta, cuando lo haya.
          example: "0"
        holder_name:
          type:
            - string
            - "null"
          maxLength: 255
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          maxLength: 20
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
      required:
        - name
        - bank_id
        - agency
        - account_number
    BankAccountUpdateRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Alias de la cuenta, para el operador.
          example: Conta principal Itaú
        bank_id:
          type: string
          format: uuid
          description: UUID del banco (vea `/banks`).
        type:
          type: string
          enum:
            - checking
            - savings
          description: "`checking` (corriente) o `savings` (ahorro)."
        agency:
          type: string
          minLength: 1
          maxLength: 50
          description: Agencia, solo dígitos.
          example: "1234"
        agency_digit:
          type:
            - string
            - "null"
          maxLength: 5
          description: Dígito de la agencia, cuando lo haya.
        account_number:
          type: string
          minLength: 1
          maxLength: 50
          description: Número de cuenta, solo dígitos.
          example: "56789"
        account_digit:
          type:
            - string
            - "null"
          maxLength: 5
          description: Dígito de la cuenta, cuando lo haya.
          example: "0"
        holder_name:
          type:
            - string
            - "null"
          maxLength: 255
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          maxLength: 20
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
    PixKeyV1:
      type: object
      properties:
        id:
          type: string
          format: uuid
        public_id:
          type: string
          format: uuid
        external_id:
          type:
            - string
            - "null"
          description: Identificador en el sistema de origen (reservado a la integración con Financeiro Inteligente).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        key:
          type: string
          description: La clave, sin máscara (documentos solo con dígitos, teléfono con `+55`, correo y aleatoria en minúsculas).
          example: "12345678000190"
        key_type:
          type: string
          enum:
            - cpf
            - cnpj
            - email
            - phone
            - random
          description: "Tipo de clave: `cpf`, `cnpj`, `email`, `phone` o `random`."
        description:
          type:
            - string
            - "null"
          description: 'Descripción libre para el operador (ej.: "Pix principal").'
          example: Pix principal
        holder_name:
          type:
            - string
            - "null"
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
          example: "12345678000190"
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        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_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_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
      required:
        - id
        - public_id
        - external_id
        - company_id
        - key
        - key_type
        - description
        - holder_name
        - holder_document
        - active
        - metadata
        - custom_metadata
        - created_via
        - created_by_email
        - updated_via
        - updated_by_email
        - created_at
        - updated_at
    PixKeyListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/PixKeyV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    PixKeyResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PixKeyV1"
      required:
        - data
    PixKeyCreateRequest:
      type: object
      properties:
        key:
          type: string
          minLength: 1
          maxLength: 255
          description: La clave, sin máscara (documentos solo con dígitos, teléfono con `+55`, correo y aleatoria en minúsculas).
          example: financeiro@empresa.com.br
        key_type:
          type: string
          enum:
            - cpf
            - cnpj
            - email
            - phone
            - random
          description: "Tipo de clave: `cpf`, `cnpj`, `email`, `phone` o `random`."
        description:
          type:
            - string
            - "null"
          maxLength: 255
          description: 'Descripción libre para el operador (ej.: "Pix principal").'
        holder_name:
          type:
            - string
            - "null"
          maxLength: 255
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          maxLength: 20
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
      required:
        - key
    PixKeyUpdateRequest:
      type: object
      properties:
        key:
          type: string
          minLength: 1
          maxLength: 255
          description: La clave, sin máscara (documentos solo con dígitos, teléfono con `+55`, correo y aleatoria en minúsculas).
          example: financeiro@empresa.com.br
        key_type:
          type: string
          enum:
            - cpf
            - cnpj
            - email
            - phone
            - random
          description: "Tipo de clave: `cpf`, `cnpj`, `email`, `phone` o `random`."
        description:
          type:
            - string
            - "null"
          maxLength: 255
          description: 'Descripción libre para el operador (ej.: "Pix principal").'
        holder_name:
          type:
            - string
            - "null"
          maxLength: 255
          description: Titular mostrado al cliente. Vacío usa la razón social de la empresa emisora de la factura (o de la organización).
        holder_document:
          type:
            - string
            - "null"
          maxLength: 20
          description: CPF/CNPJ del titular, solo dígitos. Vacío usa el documento de la empresa emisora (o de la organización).
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Empresa emisora a la que pertenece (opcional).
        active:
          type: boolean
          description: Solo los destinos activos pueden elegirse en un nuevo cobro.
    TransferDestinationDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
          required:
            - deleted
      required:
        - data
    TaxPeriodV1:
      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 en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
          description: UUID de la empresa emisora.
        period_type:
          type: string
          enum:
            - monthly
            - quarterly
          description: "Tipo del período: `monthly` (mensual) o `quarterly` (trimestral)."
        year:
          type: integer
          description: Año de competencia.
          example: 2026
        month:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 12
          description: Mes de competencia (1 a 12) — solo en períodos mensuales.
        quarter:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 4
          description: Trimestre de competencia (1 a 4) — solo en períodos trimestrales.
        status:
          type: string
          enum:
            - open
            - calculated
            - closed
          description: "Estado del período: `open`, `calculated` o `closed`."
        gross_revenue:
          type: number
          description: Ingreso bruto calculado en el período, en BRL (float, hasta 4 decimales).
          example: 1000
        taxable_revenue:
          type: number
          description: Ingreso tributable en el período, en BRL (float, hasta 4 decimales).
        iss_due:
          type: number
          description: ISS adeudado en el período, en BRL (float, hasta 4 decimales).
        pis_due:
          type: number
          description: PIS adeudado en el período, en BRL (float, hasta 4 decimales).
        cofins_due:
          type: number
          description: COFINS adeudado en el período, en BRL (float, hasta 4 decimales).
        irpj_due:
          type: number
          description: IRPJ adeudado (estimación mensual), en BRL (float, hasta 4 decimales).
        csll_due:
          type: number
          description: CSLL adeudado (estimación mensual), en BRL (float, hasta 4 decimales).
        irrf_to_compensate:
          type: number
          description: IRRF retenido pendiente de compensación, en BRL (float, hasta 4 decimales).
        csrf_to_compensate:
          type: number
          description: CSRF (PIS/COFINS/CSLL retenidos) a compensar, en BRL (float, hasta 4 decimales).
        iss_to_compensate:
          type: number
          description: ISS retenido pendiente de compensación, en BRL (float, hasta 4 decimales).
        das_estimated:
          type:
            - number
            - "null"
          description: DAS estimado (Simples Nacional), en BRL (float, hasta 4 decimales).
        simples_effective_rate:
          type:
            - string
            - "null"
          description: Alícuota efectiva del Simples Nacional aplicada (porcentaje).
        simples_annex:
          type:
            - string
            - "null"
          description: "Anexo del Simples Nacional aplicable (ej.: `annex_iii`, `annex_v`)."
        cbs_due:
          type: number
          description: CBS adeudado (reforma tributaria 2026+), en BRL (float, hasta 4 decimales).
        ibs_due:
          type: number
          description: IBS adeudado (reforma tributaria 2026+), en BRL (float, hasta 4 decimales).
        calculation_log:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Registro JSON de la memoria de cálculo (régimen, NFes consideradas, alícuotas).
        closed_at:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora en que se cerró el período.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos de solo lectura generados por el sistema.
        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
      required:
        - id
        - public_id
        - external_id
        - company_id
        - period_type
        - year
        - month
        - quarter
        - status
        - gross_revenue
        - taxable_revenue
        - iss_due
        - pis_due
        - cofins_due
        - irpj_due
        - csll_due
        - irrf_to_compensate
        - csrf_to_compensate
        - iss_to_compensate
        - das_estimated
        - simples_effective_rate
        - simples_annex
        - cbs_due
        - ibs_due
        - calculation_log
        - closed_at
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    TaxPeriodListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/TaxPeriodV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    TaxPeriodResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/TaxPeriodV1"
      required:
        - data
    TaxPeriodCreateRequest:
      type: object
      properties:
        company_id:
          type: string
          format: uuid
          description: UUID de la empresa emisora. Omita para usar la empresa por defecto de la organización.
        year:
          type: integer
          minimum: 2020
          maximum: 2100
          description: "Año de competencia (ej.: `2026`)."
          example: 2026
        month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de competencia (1 a 12).
          example: 6
        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:
        - year
        - month
    TaxPeriodUpdateRequest:
      type: object
      properties:
        action:
          type: string
          enum:
            - recalculate
            - close
            - reopen
          description: "Acción a ejecutar: `recalculate`, `close` o `reopen`."
      required:
        - action
    TaxPeriodDeletedResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            deleted:
              type: boolean
              example: true
          required:
            - deleted
      required:
        - data
    WithholdingV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type: string
          format: uuid
          description: UUID de la organización propietaria de la retención.
        invoice_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la factura asociada, cuando exista.
        nfe_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la NF-e asociada, cuando exista.
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - csrf
            - inss
            - cbs
            - ibs
          description: "Tipo del tributo retenido: `iss`, `pis`, `cofins`, `csll`, `irpj`, `irrf`, `csrf`, `inss`, `cbs` o `ibs`."
        base:
          type: number
          description: Base de cálculo en BRL (float, hasta 4 decimales).
          example: 1000
        rate:
          type: number
          description: "Alícuota aplicada en porcentaje (ej.: `1.5` para 1,5%)."
          example: 1.5
        amount:
          type: number
          description: Monto retenido en BRL (float, hasta 4 decimales).
          example: 15
        withholder_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro del retenedor (quien retuvo el tributo).
        status:
          type: string
          enum:
            - retained
            - compensated
            - partially_compensated
          description: "Estado de la retención: `retained`, `compensated` o `partially_compensated`."
        compensated:
          type: number
          description: Monto ya compensado/convertido en crédito, en BRL (float, hasta 4 decimales).
          example: 0
        competence_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de competencia (1–12).
        competence_year:
          type: integer
          description: Año de competencia (2000–3000).
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos libres asociados a la retenció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
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - invoice_id
        - nfe_id
        - tax_type
        - base
        - rate
        - amount
        - withholder_id
        - status
        - compensated
        - competence_month
        - competence_year
        - metadata
        - custom_metadata
        - created_at
        - updated_at
    WithholdingListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/WithholdingV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    WithholdingResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WithholdingV1"
      required:
        - data
    WithholdingConvertToCreditRequest:
      type: object
      properties:
        amount:
          type: number
          exclusiveMinimum: 0
          description: "Monto a convertir en BRL (float, hasta 4 decimales). Por defecto: saldo pendiente de la retención."
    WithholdingConvertToCreditResponse:
      type: object
      properties:
        credit:
          allOf:
            - $ref: "#/components/schemas/CreditV1"
            - description: Crédito generado por la conversión de la retención.
      required:
        - credit
    WithholdingBulkConvertRequest:
      type: object
      properties:
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - csrf
            - inss
            - cbs
            - ibs
          description: "Restringe la conversión a un tipo de tributo específico (ej.: `irrf`, `pis`, `cofins`)."
        competence_year:
          type: integer
          minimum: 2000
          maximum: 3000
          description: Restringe la conversión al año de competencia indicado.
        competence_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Restringe la conversión al mes de competencia indicado (1–12).
    WithholdingBulkConvertResponse:
      type: object
      properties:
        credits:
          type: array
          items:
            $ref: "#/components/schemas/CreditV1"
          description: Lista de créditos generados por la conversión.
        total_converted:
          type: integer
          description: Cantidad total de retenciones convertidas en créditos.
        total_amount:
          type: number
          description: Suma de los montos convertidos en BRL (float, hasta 4 decimales).
      required:
        - credits
        - total_converted
        - total_amount
    WithholdingCreateRequest:
      type: object
      properties:
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - csrf
            - inss
            - cbs
            - ibs
          description: Tributo retenido.
        base:
          type: number
          minimum: 0
          description: Base de cálculo, en BRL (float, hasta 4 decimales).
          example: 1000
        rate:
          type: number
          minimum: 0
          description: Alícuota aplicada, en porcentaje.
          example: 1.5
        amount:
          type: number
          minimum: 0
          description: Monto retenido, en BRL (float, hasta 4 decimales).
          example: 15
        withholder_id:
          type: string
          format: uuid
          description: Cuenta de cobro que efectuó la retención.
        competence_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de competencia (1–12).
        competence_year:
          type: integer
          minimum: 2000
          maximum: 3000
          description: Año de competencia.
        invoice_id:
          type: string
          format: uuid
          description: Factura de origen, cuando exista.
        nfe_id:
          type: string
          format: uuid
          description: Nota fiscal relacionada, cuando exista.
        metadata:
          type: object
          additionalProperties: {}
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
      required:
        - tax_type
        - base
        - rate
        - amount
        - withholder_id
        - competence_month
        - competence_year
    WithholdingUpdateRequest:
      type: object
      properties:
        competence_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de competencia (1–12).
        competence_year:
          type: integer
          minimum: 2000
          maximum: 3000
          description: Año de competencia.
        metadata:
          type: object
          additionalProperties: {}
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
    ServiceItemV1:
      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 en su sistema externo, para idempotencia/sincronización.
        organization_id:
          type: string
          format: uuid
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora asociada al ítem. `null` cuando el ítem aplica a todas las empresas de la organización.
        name:
          type: string
          description: Nombre del ítem de servicio (mostrado en facturas y NFS-e).
        description:
          type:
            - string
            - "null"
          description: Descripción opcional del servicio.
        internal_code:
          type: string
          description: Código interno del ítem — inmutable después de la creación.
        lc116_code:
          type: string
          description: Código de servicio según la Ley Complementaria 116/2003 (p. ej. `01.05`).
          example: "01.05"
        municipal_code:
          type:
            - string
            - "null"
          description: Código municipal del servicio, cuando el municipio exige codificación propia.
        nbs_code:
          type:
            - string
            - "null"
          description: Código NBS — Nomenclatura Brasileña de Servicios.
        cnae_code:
          type:
            - string
            - "null"
          description: Código CNAE relacionado con el servicio prestado.
        simples_annex:
          type:
            - string
            - "null"
          enum:
            - annex_iii
            - annex_iv
            - annex_v
          description: "Anexo del Simples Nacional aplicable al servicio: `annex_iii`, `annex_iv` o `annex_v`."
        default_iss_rate:
          type:
            - string
            - "null"
          description: Alícuota predeterminada de ISS en puntos porcentuales (p. ej. `2.5` representa 2,5 %). Decimal con hasta dos posiciones.
          example: "2.50"
        c_class_trib:
          type:
            - string
            - "null"
          description: Clasificación tributaria (CST IBS/CBS) aplicable al ítem.
        cbs_ibs_category:
          type:
            - string
            - "null"
          description: Categoría CBS/IBS del ítem, según la reforma tributaria.
        indop_code:
          type:
            - string
            - "null"
          description: Indicador de Operación (`indOp`) usado en la NFS-e SNNFSE.
        is_active:
          type: boolean
          description: Cuando es `false`, el ítem no puede seleccionarse en nuevas facturas o NFS-e.
        metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos internos del ítem (uso de la plataforma).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        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
      required:
        - id
        - public_id
        - external_id
        - organization_id
        - company_id
        - name
        - description
        - internal_code
        - lc116_code
        - municipal_code
        - nbs_code
        - cnae_code
        - simples_annex
        - default_iss_rate
        - c_class_trib
        - cbs_ibs_category
        - indop_code
        - is_active
        - metadata
        - custom_metadata
        - created_via
        - created_via_other
        - created_by_email
        - updated_via
        - updated_via_other
        - updated_by_email
        - created_at
        - updated_at
    ServiceItemListResponse:
      type: object
      properties:
        data:
          type: array
          items:
            $ref: "#/components/schemas/ServiceItemV1"
        meta:
          $ref: "#/components/schemas/PaginationMeta"
      required:
        - data
        - meta
    ServiceItemResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ServiceItemV1"
      required:
        - data
    ServiceItemCreateRequest:
      type: object
      properties:
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora asociada. Omite o envía `null` para un ítem aplicable a todas las empresas.
        name:
          type: string
          minLength: 1
          description: Nombre del ítem de servicio.
        description:
          type:
            - string
            - "null"
          description: Descripción opcional.
        internal_code:
          type: string
          minLength: 1
          description: Código interno del ítem — inmutable después de la creación.
        lc116_code:
          type: string
          minLength: 1
          description: Código LC 116/2003 del servicio (p. ej. `01.05`).
          example: "01.05"
        municipal_code:
          type:
            - string
            - "null"
          description: Código municipal del servicio, cuando corresponda.
        nbs_code:
          type:
            - string
            - "null"
          description: Código NBS.
        cnae_code:
          type:
            - string
            - "null"
          description: Código CNAE relacionado.
        simples_annex:
          type:
            - string
            - "null"
          enum:
            - annex_iii
            - annex_iv
            - annex_v
          description: "Anexo del Simples Nacional aplicable: `annex_iii`, `annex_iv` o `annex_v`."
        default_iss_rate:
          type:
            - number
            - "null"
          description: Alícuota predeterminada de ISS en puntos porcentuales (p. ej. `2.5`).
          example: 2.5
        c_class_trib:
          type:
            - string
            - "null"
          description: Clasificación tributaria CST IBS/CBS.
        cbs_ibs_category:
          type:
            - string
            - "null"
          description: Categoría CBS/IBS del ítem.
        indop_code:
          type:
            - string
            - "null"
          description: Indicador de Operación (`indOp`) de la NFS-e SNNFSE.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
      required:
        - name
        - internal_code
        - lc116_code
    ServiceItemUpdateRequest:
      type: object
      properties:
        external_id:
          type:
            - string
            - "null"
          description: Nuevo identificador en su sistema externo. Envía `null` para limpiar.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: Nueva empresa emisora asociada. Envía `null` para desasociar.
        name:
          type: string
          minLength: 1
          description: Nuevo nombre del ítem.
        description:
          type:
            - string
            - "null"
          description: Nueva descripción. Envía `null` para limpiar.
        lc116_code:
          type: string
          minLength: 1
          description: Nuevo código LC 116/2003.
        municipal_code:
          type:
            - string
            - "null"
          description: Nuevo código municipal. Envía `null` para limpiar.
        nbs_code:
          type:
            - string
            - "null"
          description: Nuevo código NBS. Envía `null` para limpiar.
        cnae_code:
          type:
            - string
            - "null"
          description: Nuevo código CNAE. Envía `null` para limpiar.
        simples_annex:
          type:
            - string
            - "null"
          enum:
            - annex_iii
            - annex_iv
            - annex_v
          description: Nuevo anexo del Simples Nacional. Envía `null` para limpiar.
        default_iss_rate:
          type:
            - number
            - "null"
          description: Nueva alícuota predeterminada de ISS en puntos porcentuales. Envía `null` para limpiar.
        c_class_trib:
          type:
            - string
            - "null"
          description: Nueva clasificación tributaria CST IBS/CBS. Envía `null` para limpiar.
        cbs_ibs_category:
          type:
            - string
            - "null"
          description: Nueva categoría CBS/IBS. Envía `null` para limpiar.
        indop_code:
          type:
            - string
            - "null"
          description: Nuevo Indicador de Operación (`indOp`). Envía `null` para limpiar.
        is_active:
          type: boolean
          description: Activa (`true`) o desactiva (`false`) el ítem de servicio.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos arbitrarios definidos por el cliente (clave/valor).
        custom_metadata_mode:
          type: string
          enum:
            - replace
            - merge
          description: Cómo se reconcilia el `custom_metadata` enviado con el valor almacenado. `replace` (por defecto) reemplaza todo el objeto; `merge` hace un deep merge sobre el valor actual — los objetos anidados se combinan recursivamente, los escalares y arrays reemplazan la clave, y las claves `null` se mantienen (no eliminan la clave). Aceptado solo en la actualización.
          example: merge
    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 en Kobana OAuth, cuando ya se conoce.
        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.: `billing_manager`)."
          example: billing_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).
    ProposalItemCreateRequest:
      type: object
      properties:
        product_id:
          type: string
          format: uuid
          description: UUID del producto. **Obligatorio**.
        price_id:
          type: string
          format: uuid
          description: UUID del precio. **Obligatorio**.
        quantity:
          type: number
          minimum: 1
          description: "Cantidad. Por defecto: 1."
        unit_amount:
          type: number
          minimum: 0
          description: Valor unitario en BRL (float, hasta 4 decimales).
        metadata:
          type: object
          additionalProperties: {}
          description: Metadatos arbitrarios del ítem.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Campos personalizados del ítem.
      required:
        - product_id
        - price_id
        - unit_amount
    CreditUsageDailyInput:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: ID de la cuenta de cobro. Envía este **o** `billing_account_public_id`.
        billing_account_public_id:
          type: string
          format: uuid
          description: Identificador público de la cuenta de cobro (tiene precedencia sobre `billing_account_id`).
        product_id:
          type: string
          format: uuid
          description: ID del producto de créditos. Envía este **o** `product_slug`.
        product_slug:
          type: string
          description: Slug del producto de créditos (tiene precedencia sobre `product_id`).
        usage_date:
          type: string
          description: Día del consumo (`YYYY-MM-DD`).
          example: 2026-10-13
        requests:
          type: integer
          minimum: 0
          description: Cantidad de solicitudes.
        prompt_tokens:
          type: integer
          minimum: 0
          description: Tokens de prompt (entrada).
        completion_tokens:
          type: integer
          minimum: 0
          description: Tokens de respuesta (salida).
        total_tokens:
          type: integer
          minimum: 0
          description: Total de tokens. Si se omite, `prompt_tokens + completion_tokens`.
        credits_consumed:
          type: number
          minimum: 0
          description: Créditos consumidos, en la unidad del producto (hasta 6 decimales).
          example: 0.07
        calculated_at:
          type: string
          format: date-time
          description: "Cuándo se calculó el consumo en el origen (ISO 8601). Por defecto: ahora."
        metadata:
          type: object
          additionalProperties: {}
          description: Datos libres del origen, guardados tal como llegaron.
      required:
        - usage_date
        - credits_consumed
    CreditUsageDailyRequest:
      anyOf:
        - $ref: "#/components/schemas/CreditUsageDailyInput"
        - type: object
          properties:
            records:
              type: array
              items:
                $ref: "#/components/schemas/CreditUsageDailyInput"
              maxItems: 100
          required:
            - records
    CreditUsageDailyResult:
      type: object
      properties:
        id:
          type: string
          format: uuid
        billing_account_id:
          type: string
          format: uuid
        product_id:
          type: string
          format: uuid
        usage_date:
          type: string
        success:
          type: boolean
        overwritten:
          type: boolean
          description: "`true` cuando ya había consumo para ese día y fue reemplazado."
        error:
          type: string
      required:
        - success
    CreditUsageDailyResponse:
      type: object
      properties:
        success:
          type: boolean
        processed:
          type: integer
        failed:
          type: integer
        partial:
          type: boolean
        results:
          anyOf:
            - $ref: "#/components/schemas/CreditUsageDailyResult"
            - type: array
              items:
                $ref: "#/components/schemas/CreditUsageDailyResult"
      required:
        - success
        - processed
        - results
    CreditUsageReport:
      type: object
      properties:
        products:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              slug:
                type: string
              unit_label:
                type:
                  - string
                  - "null"
              status:
                type: string
              product_group_id:
                type:
                  - string
                  - "null"
                format: uuid
                description: Familia (grupo de productos) del producto de créditos.
              product_group_name:
                type:
                  - string
                  - "null"
                description: Nombre de la familia del producto.
              unit_amount:
                type:
                  - number
                  - "null"
                description: Precio por defecto de un crédito, en BRL.
              increment:
                type: integer
            required:
              - id
              - name
              - slug
              - unit_label
              - status
              - product_group_id
              - product_group_name
              - unit_amount
              - increment
        product_id:
          type:
            - string
            - "null"
          format: uuid
          description: Producto al que se refiere el informe. Null cuando la organización no tiene producto de créditos.
        period:
          type: object
          properties:
            start_date:
              type: string
            end_date:
              type: string
          required:
            - start_date
            - end_date
        totals:
          type: object
          properties:
            requests:
              type: integer
              description: Cantidad de solicitudes.
            prompt_tokens:
              type: integer
              description: Tokens de prompt (entrada).
            completion_tokens:
              type: integer
              description: Tokens de respuesta (salida).
            total_tokens:
              type: integer
              description: Total de tokens.
            credits_consumed:
              type: number
              description: Créditos consumidos, en la unidad del producto (hasta 6 decimales).
          required:
            - requests
            - prompt_tokens
            - completion_tokens
            - total_tokens
            - credits_consumed
        daily:
          type: array
          items:
            type: object
            properties:
              date:
                type: string
              requests:
                type: integer
                description: Cantidad de solicitudes.
              prompt_tokens:
                type: integer
                description: Tokens de prompt (entrada).
              completion_tokens:
                type: integer
                description: Tokens de respuesta (salida).
              total_tokens:
                type: integer
                description: Total de tokens.
              credits_consumed:
                type: number
                description: Créditos consumidos, en la unidad del producto (hasta 6 decimales).
            required:
              - date
              - requests
              - prompt_tokens
              - completion_tokens
              - total_tokens
              - credits_consumed
        balance:
          type: object
          properties:
            purchased:
              type: number
              description: Créditos comprados en facturas pagadas.
            consumed:
              type: number
              description: Créditos consumidos hasta hoy.
            available:
              type: number
              description: "Saldo disponible: comprados − consumidos."
            pending_purchase:
              type: number
              description: Créditos en facturas de compra aún abiertas.
          required:
            - purchased
            - consumed
            - available
            - pending_purchase
          description: Saldo actual (independiente del período).
      required:
        - products
        - product_id
        - period
        - totals
        - daily
        - balance
    CreditUsageReportResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CreditUsageReport"
      required:
        - data
    CreditPurchaseCreateRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: ID de la cuenta de cobro. Envía este **o** `billing_account_public_id`.
        billing_account_public_id:
          type: string
          format: uuid
          description: Identificador público de la cuenta de cobro.
        product_id:
          type: string
          format: uuid
          description: Producto de tipo `credits`.
        price_id:
          type: string
          format: uuid
          description: "Precio a cobrar. Por defecto: el precio activo por defecto del producto."
        quantity:
          type: integer
          minimum: 1
          description: Cantidad de créditos (entera; múltiplo del incremento del producto).
          example: 100
        collection_method:
          type: string
          enum:
            - charge_automatically
            - manual_charge
          description: "`manual_charge` (por defecto): el cliente paga la factura. `charge_automatically`: cobra la tarjeta por defecto al finalizar."
        due_date:
          type: string
          description: "Vencimiento. Por defecto: el plazo de pago de la cuenta."
      required:
        - product_id
        - quantity
    SubscriptionUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/SubscriptionV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    SubscriptionUpsertRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro que recibirá esta suscripción.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
        plan_id:
          type: string
          format: uuid
          description: UUID del plan. Obligatorio cuando no se envía `items`.
        product_group_id:
          type: string
          format: uuid
        billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        collection_method:
          type:
            - string
            - "null"
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
        trial_end:
          type: string
          format: date-time
          description: Fecha de finalización del trial (ISO 8601).
        trial_period_days:
          type: integer
          minimum: 0
          description: Alternativa a `trial_end`. Días de trial a partir de la creación.
        proration_behavior:
          type: string
          enum:
            - create_prorations
            - none
            - always_invoice
        nfe_issuance_policy:
          type: string
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
        items:
          type: array
          items:
            type: object
            properties:
              product_id:
                type: string
                format: uuid
              price_id:
                type: string
                format: uuid
              quantity:
                type: integer
                minimum: 1
                default: 1
              unit_amount:
                type: number
                minimum: 0
                description: Precisión de 4 decimales (float, hasta 4 decimales). Sobrescribe el importe del precio.
            required:
              - product_id
              - price_id
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: "Permanencia: número de meses contratados (copiado de la propuesta aceptada). Dentro de la ventana de permanencia — inicio de la suscripción + meses — el cliente no puede cancelar por el portal. Use `null` para quitar."
        notes:
          type:
            - string
            - "null"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
        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.
    SubscriptionItemsExecuteResponse:
      type: object
      properties:
        data:
          type: object
          properties:
            success:
              type: boolean
            item_change_id:
              type:
                - string
                - "null"
              format: uuid
            invoice_id:
              type:
                - string
                - "null"
              format: uuid
            credit_id:
              type:
                - string
                - "null"
              format: uuid
          required:
            - success
            - item_change_id
            - invoice_id
            - credit_id
      required:
        - data
    SubscriptionItemOp:
      oneOf:
        - type: object
          properties:
            op:
              type: string
              enum:
                - add
            product_id:
              type: string
              format: uuid
            price_id:
              type: string
              format: uuid
            quantity:
              type: integer
              exclusiveMinimum: 0
          required:
            - op
            - product_id
            - price_id
            - quantity
        - type: object
          properties:
            op:
              type: string
              enum:
                - remove
            subscription_item_id:
              type: string
              format: uuid
          required:
            - op
            - subscription_item_id
        - type: object
          properties:
            op:
              type: string
              enum:
                - update_qty
            subscription_item_id:
              type: string
              format: uuid
            quantity:
              type: integer
              exclusiveMinimum: 0
          required:
            - op
            - subscription_item_id
            - quantity
        - type: object
          properties:
            op:
              type: string
              enum:
                - update_price
            subscription_item_id:
              type: string
              format: uuid
            price_id:
              type: string
              format: uuid
          required:
            - op
            - subscription_item_id
            - price_id
        - type: object
          properties:
            op:
              type: string
              enum:
                - update_unit_amount
            subscription_item_id:
              type: string
              format: uuid
            unit_amount:
              type: number
              minimum: 0
              description: Nuevo valor unitario, en BRL (float, hasta 4 decimales).
              example: 99.9
          required:
            - op
            - subscription_item_id
            - unit_amount
    SubscriptionItemsExecuteRequest:
      type: object
      properties:
        changes:
          type: array
          items:
            $ref: "#/components/schemas/SubscriptionItemOp"
          minItems: 1
          maxItems: 50
          description: Operaciones a aplicar, de 1 a 50. Cada ítem se discrimina por `op`.
        timing:
          type: string
          enum:
            - immediate
            - end_of_period
          description: "Cuándo aplicar: `immediate` (predeterminado) o `end_of_period`."
        reason:
          type: string
          description: Motivo libre, guardado junto al registro de cambio.
        idempotency_key:
          type: string
          description: Clave de idempotencia. El encabezado `Idempotency-Key` tiene precedencia sobre este campo.
      required:
        - changes
    BillingAccountUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/BillingAccountV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    BillingAccountUpsertRequest:
      type: object
      properties:
        customer:
          allOf:
            - $ref: "#/components/schemas/BillingAccountCustomerInput"
            - description: Cliente a asociar — existente o nuevo.
        external_id:
          type: string
          description: Identificador externo de la cuenta en el sistema del cliente.
        billing_email:
          type: string
          format: email
          description: "Correo de cobro. Por defecto: `customer.email`."
        payment_terms_days:
          type: integer
          minimum: 1
          maximum: 90
          description: "Plazo de vencimiento de factura en días (1–90). Por defecto: el plazo predeterminado configurado en la organización (10 cuando no está configurado)."
        auto_collection:
          type: boolean
          description: "Habilita el cobro automático. Por defecto: `true`."
        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.
    PlanUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    PlanUpsertRequest:
      type: object
      properties:
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
        plan_group_id:
          type:
            - string
            - "null"
          format: uuid
        name:
          type: string
          minLength: 1
          maxLength: 255
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9-]+$
          description: Solo letras minúsculas, dígitos y guiones.
        description:
          type:
            - string
            - "null"
        status:
          type: string
          enum:
            - draft
            - active
            - archived
        plan_type:
          type: string
          enum:
            - standard
            - custom
            - promotional
          description: "Por defecto: `standard`."
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Por defecto: `public`."
        features:
          type: array
          items:
            type: string
        limits:
          type: object
          properties:
            users:
              type: integer
            subaccounts:
              type: integer
            operations_per_month:
              type: integer
            api_requests_per_day:
              type: integer
        trial_period_days:
          type: integer
          minimum: 0
          maximum: 90
        default_billing_cycle:
          type: string
          enum:
            - monthly
            - quarterly
            - semiannual
            - annual
        available_billing_cycles:
          type: array
          items:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
        items:
          type: array
          items:
            $ref: "#/components/schemas/PlanItemInput"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
        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.
    PlanGroupUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PlanGroupV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    PlanGroupUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del grupo de planes.
        slug:
          type: string
          minLength: 1
          maxLength: 100
          description: Identificador legible (opcional). Generado automáticamente si se omite.
        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.
    ProductUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProductV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    ProductUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del producto.
        slug:
          type: string
          minLength: 1
          maxLength: 100
          pattern: ^[a-z0-9_-]+$
          description: Slug único dentro del grupo. Acepta solo `[a-z0-9_-]+`.
        description:
          type: string
        product_type:
          type: string
          enum:
            - base
            - addon_quantity
            - addon_fixed
            - metered
            - one_time_fixed
            - one_time_quantity
            - credits
          description: "Tipo del producto. Por defecto: `base`."
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal. Por defecto: `public`."
        unit_label:
          type: string
        increment:
          type: integer
          exclusiveMinimum: 0
          description: "Incremento mínimo. Por defecto: `1`."
        website_url:
          type: string
          format: uri
        is_required:
          type: boolean
        parent_product_id:
          type: string
          format: uuid
        product_group_id:
          type: string
          format: uuid
        company_id:
          type: string
          format: uuid
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
        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.
    ProductGroupUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProductGroupV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    ProductGroupUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre del grupo.
        slug:
          type: string
          description: Slug del grupo. Generado a partir del nombre cuando se omite.
        visibility:
          type: string
          enum:
            - public
            - private
          description: "Visibilidad en el portal del cliente. Por defecto: `public`."
        company_id:
          type:
            - string
            - "null"
          format: uuid
        proposal_template_id:
          type:
            - string
            - "null"
          format: uuid
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
        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.
    CompanyUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CompanyV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    CompanyUpsertRequest:
      type: object
      properties:
        parent_company_id:
          type: string
          format: uuid
          description: UUID de la matriz al crear una sucursal. Omite para crear una matriz.
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre comercial de la empresa.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        legal_name:
          type: string
          maxLength: 255
          description: Razón social.
        document_type:
          type: string
          enum:
            - cpf
            - cnpj
          description: "Tipo de documento: `cpf` o `cnpj`. Solo `cnpj` puede tener sucursales."
        document_number:
          type: string
          minLength: 11
          maxLength: 18
          description: CPF o CNPJ (con o sin máscara — se normalizará a solo dígitos).
        email:
          type: string
          format: email
          description: Correo principal de la empresa.
        phone:
          type: string
          description: Teléfono principal de la empresa. Cuando se informa, se añade al array `phones`.
        addresses:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de direcciones de la empresa.
        emails:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de correos adicionales. Si se omite, se usa el `email` principal.
        phones:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de teléfonos de la empresa.
        websites:
          type: array
          items:
            type: object
            additionalProperties: {}
          description: Lista de sitios web de la empresa.
        is_default:
          type: boolean
          description: Cuando es `true`, marca esta empresa como predeterminada de la organización. Solo las matrices pueden ser predeterminadas.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados (clave/valor libre).
        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.
    CouponUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CouponV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    CouponUpsertRequest:
      type: object
      properties:
        code:
          type: string
          minLength: 1
          description: Código público del cupón — único por organización.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        name:
          type: string
          minLength: 1
          description: Nombre interno del cupón.
        description:
          type: string
          description: Descripción opcional.
        discount_type:
          type: string
          enum:
            - percentage
            - fixed_amount
          description: "Tipo de descuento: `percentage` o `fixed_amount`."
        discount_value:
          type: number
          minimum: 0
          description: Valor del descuento. Para `percentage`, entero entre `0` y `100`. Para `fixed_amount`, importe en BRL (float, hasta 4 decimales).
        currency:
          type: string
          description: "Moneda ISO 4217. Por defecto: `BRL`."
        min_purchase:
          type: number
          minimum: 0
          description: Importe mínimo de la factura, en BRL (float, hasta 4 decimales), para que el cupón pueda aplicarse.
        max_discount:
          type: number
          minimum: 0
          description: Tope absoluto del descuento, en BRL (float, hasta 4 decimales).
        usage_limit:
          type: integer
          exclusiveMinimum: 0
          description: Máximo total de canjes en la organización. Omite para ilimitado.
        usage_limit_per_user:
          type: integer
          exclusiveMinimum: 0
          description: Máximo de canjes por cuenta de cobro. Omite para ilimitado.
        valid_from:
          type: string
          description: Inicio del periodo de validez (ISO 8601 — fecha o fecha/hora).
        valid_until:
          type: string
          description: Fin del periodo de validez (ISO 8601 — fecha o fecha/hora).
        applies_to:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - description: Restringe el cupón a planes y/o productos.
        excludes:
          allOf:
            - $ref: "#/components/schemas/CouponTargetV1"
            - description: Lista de planes y/o productos donde el cupón no puede aplicarse.
        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.
    CreditUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/CreditV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    CreditUpsertRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro que recibirá el crédito.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
          description: UUID opcional de la `company` a la que está vinculado el crédito. Cuando se informa, restringe la aplicación del crédito a facturas de la misma `company`.
        type:
          type: string
          enum:
            - promotional
            - adjustment
            - refund
            - manual
          description: "Tipo de crédito: `promotional`, `adjustment`, `refund` o `manual`."
        amount:
          type: number
          exclusiveMinimum: 0
          description: Monto del crédito en BRL (float, hasta 4 decimales). Debe ser un entero positivo.
          example: 100
        description:
          type: string
          maxLength: 500
          description: Descripción libre (hasta 500 caracteres) — se muestra en el extracto y en el audit log.
        expires_at:
          type: string
          format: date-time
          description: Fecha y hora de expiración (ISO8601). Después de esa fecha el saldo restante se descarta.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Metadatos personalizados validados contra el esquema de la organización.
        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.
    InvoiceUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/InvoiceV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    InvoiceUpsertRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro destino. **Obligatorio**.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type: string
          format: uuid
          description: "UUID de la empresa emisora. Por defecto: empresa por defecto de la organización."
        subscription_id:
          type: string
          format: uuid
          description: UUID de la suscripción de origen.
        product_group_id:
          type: string
          format: uuid
          description: UUID del grupo de productos.
        collection_method:
          type: string
          enum:
            - charge_automatically
            - manual_charge
            - manual_invoice
          description: "Método de cobro. Por defecto: `manual_invoice`."
        due_date:
          type: string
          description: "Fecha de vencimiento. Por defecto: hoy + `payment_terms_days` de la cuenta."
        description:
          type: string
          description: Descripción libre mostrada al inicio de la factura.
        footer:
          type: string
          description: Pie libre mostrado al final de la factura.
        line_items:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceLineItemCreateInput"
          minItems: 1
          maxItems: 200
          description: Ítems de línea. Mínimo 1.
        discount:
          type: number
          minimum: 0
          description: Descuento fijo en BRL.
        discount_description:
          type: string
          description: 'Descripción del descuento (ej.: "Descuento por pago anual (20%)").'
        installments:
          type: array
          items:
            $ref: "#/components/schemas/InvoiceInstallmentCreateInput"
          minItems: 2
          maxItems: 60
          description: Cronograma de parcelas (mínimo 2). Cada ítem tiene `amount` y `due_date`.
        nfe_issuance_policy:
          type: string
          enum:
            - disabled
            - on_finalization
            - on_full_payment
            - per_installment
          description: Política de emisión de NF-e para facturas en cuotas.
        period_start:
          type: string
          description: Inicio del período de competencia (autocompletado en facturas de suscripción).
        period_end:
          type: string
          description: Fin del período de competencia (autocompletado en facturas de suscripción).
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
        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.
    PaymentMethodUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/PaymentMethodV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    PaymentMethodUpsertRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro propietaria del método de pago.
        type:
          type: string
          enum:
            - card
            - bank_slip
            - pix
            - bank_transfer
          description: "Tipo del método: `card`, `bank_slip`, `pix` o `bank_transfer`."
        is_default:
          type: boolean
          description: Cuando es `true`, marca este método como predeterminado de la cuenta (desmarca los anteriores). El primer método creado para una cuenta también se vuelve predeterminado automáticamente.
        card:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodCardInput"
            - description: Bloque de tarjeta. Obligatorio cuando `type=card`.
        bank_account:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBankAccountInput"
            - description: Bloque de cuenta bancaria. Obligatorio cuando `type=bank_transfer`.
        billing_details:
          allOf:
            - $ref: "#/components/schemas/PaymentMethodBillingDetailsInput"
            - description: Datos de cobro opcionales (nombre, correo, teléfono, dirección) usados por el gateway.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Metadatos personalizados en formato libre (`object`).
        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.
    NfeUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/NfeV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    NfeUpsertRequest:
      type: object
      properties:
        billing_account_id:
          type: string
          format: uuid
          description: UUID de la cuenta de cobro (tomador). **Obligatorio**.
        company_id:
          type: string
          format: uuid
          description: "UUID de la empresa emisora (prestador). Por defecto: empresa por defecto de la organización."
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        invoice_id:
          type: string
          format: uuid
          description: UUID de la factura vinculada (opcional).
        transaction_id:
          type: string
          format: uuid
          description: UUID de la transacción de origen (opcional).
        amount:
          type: number
          exclusiveMinimum: 0
          description: Monto de la NF-e en BRL (float, hasta 4 decimales). **Obligatorio**, debe ser positivo.
        service_code:
          type: string
          description: Código del servicio según la tabla municipal.
        service_description:
          type: string
          description: Descripción libre del servicio prestado.
        lc116_code:
          type: string
          description: Código LC 116.
        cnae_code:
          type: string
          description: Código CNAE.
        nbs_code:
          type: string
          description: Código NBS.
        c_class_trib:
          type: string
          description: Clasificación Tributaria (cClassTrib) del IBS/CBS.
        ind_op:
          type: string
          description: Indicador de Operación (indOp) del IBS/CBS.
        rps_number:
          type: integer
          description: Número del RPS (cuando la numeración es gestionada por la aplicación).
        rps_serial_number:
          type: string
          description: Serie del RPS.
        customer:
          $ref: "#/components/schemas/NfeCustomerInput"
        taxes:
          $ref: "#/components/schemas/NfeTaxesInput"
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
        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.
    ProposalUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProposalV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    ProposalUpsertRequest:
      type: object
      properties:
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora. Usa `null` para limpiar.
        title:
          type: string
          minLength: 1
          maxLength: 255
          description: 'Título de la propuesta. Por defecto: "Proposta Comercial".'
        description:
          type:
            - string
            - "null"
          description: Descripción libre de la propuesta.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro destino (cliente existente). Obligatorio si no se informan `prospect_id` ni `prospect_data`.
        prospect_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de un prospect existente. Alternativa a `billing_account_id`/`prospect_data`.
        contact_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de un contacto existente vinculado al prospect.
        prospect_data:
          $ref: "#/components/schemas/ProspectDataInput"
        contact_data:
          $ref: "#/components/schemas/ContactDataInput"
        coupon_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del cupón a aplicar.
        template_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del template para generar el PDF.
        discount_percent:
          type:
            - number
            - "null"
          minimum: 0
          maximum: 100
          description: Porcentaje de descuento negociado (0–100), aplicado sobre el valor mensual; el descuento por ciclo se aplica sobre el valor con descuento. No lo envíe junto con `discount_amount`.
        discount_amount:
          type:
            - number
            - "null"
          minimum: 0
          description: Descuento fijo negociado por mes en BRL (float, hasta 4 decimales), aplicado sobre el valor mensual; el descuento por ciclo se aplica sobre el valor con descuento. No lo envíe junto con `discount_percent`.
          example: 50
        commitment_months:
          type:
            - integer
            - "null"
          minimum: 1
          maximum: 120
          description: Permanencia en meses (1–120). Use `null` para quitar. Copiado a la suscripción cuando se acepta la propuesta.
          example: 12
        expires_at:
          type: string
          description: Fecha de expiración.
        notes:
          type:
            - string
            - "null"
          description: Notas internas.
        items:
          type: array
          items:
            $ref: "#/components/schemas/ProposalItemInput"
          minItems: 1
          description: Ítems de la propuesta. Mínimo 1.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type:
            - object
            - "null"
          additionalProperties: {}
          description: Campos personalizados (validados contra el schema de la organización).
        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.
    ProposalTemplateUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ProposalTemplateV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    ProposalTemplateUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 255
          description: Nombre de la plantilla (único por organización).
        description:
          type:
            - string
            - "null"
          description: Descripción opcional de la plantilla.
        document_type:
          type: string
          enum:
            - google_doc
            - google_slides
          description: "Tipo de documento base: `google_doc` o `google_slides`. Por defecto: `google_doc`."
        google_doc_id:
          type: string
          minLength: 1
          description: ID del Google Doc/Slides usado como plantilla (único por organización).
        app_script_url:
          type:
            - string
            - "null"
          format: uri
          description: URL del Apps Script publicado que renderiza la plantilla, cuando aplique.
        google_drive_folder_id:
          type:
            - string
            - "null"
          description: ID de la carpeta de Google Drive donde se guardarán las copias generadas.
        is_active:
          type: boolean
          description: Cuando es `false`, crea la plantilla ya desactivada.
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
          description: Metadatos libres definidos por el cliente para correlación interna.
        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.
    TaxRuleUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/TaxRuleV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    TaxRuleUpsertRequest:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          description: Nombre legible de la regla.
        description:
          type:
            - string
            - "null"
          description: Descripción opcional de la regla.
        scope:
          type: string
          enum:
            - global
            - organization
            - company
            - service
            - customer
            - municipality
          description: "Alcance de la regla: `global`, `organization`, `company`, `service`, `customer` o `municipality`."
        priority:
          type: integer
          description: "Prioridad de la regla. Mayor valor sobrescribe reglas de menor prioridad. Por defecto: `0`."
          example: 0
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa cuando `scope = company`. La empresa debe pertenecer a la organización actual.
        service_item_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID del ítem de servicio cuando `scope = service`. El ítem debe pertenecer a la organización actual.
        billing_account_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la cuenta de cobro cuando `scope = customer`. La cuenta debe pertenecer a la organización actual.
        customer_tax_type:
          type:
            - string
            - "null"
          enum:
            - pessoa_fisica
            - pessoa_juridica
            - mei
            - simples_optante
            - entidade_publica
          description: "Tipo tributario del cliente: `pessoa_fisica`, `pessoa_juridica`, `mei`, `simples_optante` o `entidade_publica`."
        municipality:
          type:
            - string
            - "null"
          description: Código IBGE del municipio (7 dígitos) cuando `scope = municipality`.
        operation_type:
          type:
            - string
            - "null"
          enum:
            - interno
            - externo
          description: "Tipo de operación: `interno` (mismo municipio) o `externo` (municipio diferente)."
        effective_from:
          type: string
          format: date-time
          description: Fecha/hora ISO 8601 en que la regla entra en vigor.
        effective_to:
          type:
            - string
            - "null"
          format: date-time
          description: Fecha/hora ISO 8601 en que la regla deja de regir. `null` significa vigencia indeterminada.
        items:
          type: array
          items:
            $ref: "#/components/schemas/TaxRuleItemInput"
          minItems: 1
          description: Lista de ítems (alícuotas por tributo). Se requiere al menos 1 ítem.
        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.
    WithholdingUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/WithholdingV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    WithholdingUpsertRequest:
      type: object
      properties:
        tax_type:
          type: string
          enum:
            - iss
            - pis
            - cofins
            - csll
            - irpj
            - irrf
            - csrf
            - inss
            - cbs
            - ibs
          description: Tributo retenido.
        base:
          type: number
          minimum: 0
          description: Base de cálculo, en BRL (float, hasta 4 decimales).
          example: 1000
        rate:
          type: number
          minimum: 0
          description: Alícuota aplicada, en porcentaje.
          example: 1.5
        amount:
          type: number
          minimum: 0
          description: Monto retenido, en BRL (float, hasta 4 decimales).
          example: 15
        withholder_id:
          type: string
          format: uuid
          description: Cuenta de cobro que efectuó la retención.
        competence_month:
          type: integer
          minimum: 1
          maximum: 12
          description: Mes de competencia (1–12).
        competence_year:
          type: integer
          minimum: 2000
          maximum: 3000
          description: Año de competencia.
        invoice_id:
          type: string
          format: uuid
          description: Factura de origen, cuando exista.
        nfe_id:
          type: string
          format: uuid
          description: Nota fiscal relacionada, cuando exista.
        metadata:
          type: object
          additionalProperties: {}
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        custom_metadata:
          type: object
          additionalProperties: {}
        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.
    ServiceItemUpsertResponse:
      type: object
      properties:
        data:
          $ref: "#/components/schemas/ServiceItemV1"
        matched_by:
          type:
            - string
            - "null"
          description: Clave que localizó el registro existente. `null` cuando el registro fue creado.
      required:
        - data
        - matched_by
    ServiceItemUpsertRequest:
      type: object
      properties:
        external_id:
          type: string
          description: Identificador en su sistema externo, para idempotencia/sincronización.
        company_id:
          type:
            - string
            - "null"
          format: uuid
          description: UUID de la empresa emisora asociada. Omite o envía `null` para un ítem aplicable a todas las empresas.
        name:
          type: string
          minLength: 1
          description: Nombre del ítem de servicio.
        description:
          type:
            - string
            - "null"
          description: Descripción opcional.
        internal_code:
          type: string
          minLength: 1
          description: Código interno del ítem — inmutable después de la creación.
        lc116_code:
          type: string
          minLength: 1
          description: Código LC 116/2003 del servicio (p. ej. `01.05`).
          example: "01.05"
        municipal_code:
          type:
            - string
            - "null"
          description: Código municipal del servicio, cuando corresponda.
        nbs_code:
          type:
            - string
            - "null"
          description: Código NBS.
        cnae_code:
          type:
            - string
            - "null"
          description: Código CNAE relacionado.
        simples_annex:
          type:
            - string
            - "null"
          enum:
            - annex_iii
            - annex_iv
            - annex_v
          description: "Anexo del Simples Nacional aplicable: `annex_iii`, `annex_iv` o `annex_v`."
        default_iss_rate:
          type:
            - number
            - "null"
          description: Alícuota predeterminada de ISS en puntos porcentuales (p. ej. `2.5`).
          example: 2.5
        c_class_trib:
          type:
            - string
            - "null"
          description: Clasificación tributaria CST IBS/CBS.
        cbs_ibs_category:
          type:
            - string
            - "null"
          description: Categoría CBS/IBS del ítem.
        indop_code:
          type:
            - string
            - "null"
          description: Indicador de Operación (`indOp`) de la NFS-e SNNFSE.
        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.
    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 en Kobana OAuth, cuando ya se conoce.
        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.: `billing_manager`)."
          example: billing_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.billing.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`."
paths:
  /v1/subscriptions:
    get:
      tags:
        - Suscripciones
      summary: Listar suscripciones
      description: Devuelve una lista paginada de las suscripciones 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
            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
        - schema:
            type: string
            enum:
              - draft
              - trialing
              - active
              - past_due
              - canceled
              - paused
              - suspended
            description: Filtra por estado de la suscripción.
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por plan.
          required: false
          name: plan_id
          in: query
        - schema:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
            description: Filtra por periodicidad de cobro.
          required: false
          name: billing_cycle
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por empresa (UUID).
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            enum:
              - charge_automatically
              - manual_charge
              - manual_invoice
            description: "Filtra por el método de cobro: `charge_automatically`, `manual_charge` o `manual_invoice`."
          required: false
          name: collection_method
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Filtra suscripciones programadas para cancelarse al fin del período (`true`) o no (`false`).
          required: false
          name: cancel_at_period_end
          in: query
        - schema:
            type: string
            description: Filtra por el identificador externo.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por grupo de producto (UUID).
          required: false
          name: product_group_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por propuesta (UUID).
          required: false
          name: proposal_id
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Importe recurrente mínimo en reales (ej.: `50.00`)."
            example: 100
          required: false
          name: recurring_amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Importe recurrente máximo en reales (ej.: `500.00`)."
            example: 100
          required: false
          name: recurring_amount_max
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del período actual a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: current_period_start_from
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del período actual hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: current_period_start_to
          in: query
        - schema:
            type: string
            format: date
            description: Fin del período actual a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: current_period_end_from
          in: query
        - schema:
            type: string
            format: date
            description: Fin del período actual hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: current_period_end_to
          in: query
        - schema:
            type: string
            format: date
            description: Fin del trial a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: trial_end_from
          in: query
        - schema:
            type: string
            format: date
            description: Fin del trial hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: trial_end_to
          in: query
        - schema:
            type: string
            format: date
            description: Cancelado a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: canceled_after
          in: query
        - schema:
            type: string
            format: date
            description: Cancelado hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: canceled_before
          in: query
        - schema:
            type: string
            format: date
            description: Activado a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: activated_after
          in: query
        - schema:
            type: string
            format: date
            description: Activado hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: activated_before
          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-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 suscripciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionListResponse"
        "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-subscriptions
    post:
      tags:
        - Suscripciones
      summary: Crear suscripción
      description: Crea una suscripción. Es obligatorio enviar `plan_id` o `items`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscriptionCreateRequest"
      responses:
        "201":
          description: Suscripción creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions
      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-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:
        - Suscripciones
      summary: Crear o actualizar suscripción
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscriptionUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionUpsertResponse"
        "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-subscriptions
      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-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/subscriptions/{id}:
    get:
      tags:
        - Suscripciones
      summary: Obtener suscripción
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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 de la suscripción.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id
    patch:
      tags:
        - Suscripciones
      summary: Actualizar suscripción
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionUpdateRequest"
      responses:
        "200":
          description: Suscripción actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id
    delete:
      tags:
        - Suscripciones
      summary: Cancelar y eliminar suscripción (soft delete)
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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 soft delete.
          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-subscriptions-id
  /v1/subscriptions/{id}/pause:
    post:
      tags:
        - Suscripciones
      summary: Pausar suscripción
      description: Suspende el cobro manteniendo la suscripción abierta. `behavior` controla cómo se tratan las facturas generadas durante la pausa.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionPauseRequest"
      responses:
        "200":
          description: Suscripción pausada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-pause
  /v1/subscriptions/{id}/resume:
    post:
      tags:
        - Suscripciones
      summary: Reanudar suscripción pausada
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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: Suscripción reanudada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-resume
  /v1/subscriptions/{id}/cancel:
    post:
      tags:
        - Suscripciones
      summary: Cancelar suscripción
      description: Cancela inmediatamente, o programa para el fin del período cuando `cancel_at_period_end=true`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionCancelRequest"
      responses:
        "200":
          description: Suscripción cancelada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-cancel
  /v1/subscriptions/{id}/activate:
    post:
      tags:
        - Suscripciones
      summary: Activar suscripción en borrador/confirmada
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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: Suscripción activada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-activate
  /v1/subscriptions/{id}/change-plan:
    post:
      tags:
        - Suscripciones
      summary: Cambiar el plan de la suscripción
      description: Upgrade o downgrade. La prorrata sigue el `proration_behavior` de la suscripción.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionChangePlanRequest"
      responses:
        "200":
          description: Suscripción actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-change-plan
  /v1/subscriptions/{id}/change-anniversary:
    post:
      tags:
        - Suscripciones
      summary: Cambiar el aniversario (día de inicio del ciclo) de la suscripción
      description: Mueve el día del mes en que empiezan los ciclos. El ciclo en curso mantiene su inicio y se extiende hasta la víspera del nuevo día; los días añadidos se cobran a prorrata (importe del ciclo × días ÷ días del ciclo) en una factura `subscription_update`. El cambio siempre avanza la fecha, nunca la retrocede. Use `dry_run` para calcular sin aplicar.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionChangeAnniversaryRequest"
      responses:
        "200":
          description: Resultado del cambio (o de la simulación, con `dry_run`).
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: "#/components/schemas/SubscriptionChangeAnniversaryResult"
                required:
                  - data
        "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-subscriptions-id-change-anniversary
  /v1/subscriptions/{id}/revert-to-confirmed:
    post:
      tags:
        - Suscripciones
      summary: Revertir suscripción al estado confirmado
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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: Suscripción revertida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-revert-to-confirmed
  /v1/subscriptions/{id}/create-invoice:
    post:
      tags:
        - Suscripciones
      summary: Generar una factura puntual para la suscripción
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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: Factura generada.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: {}
        "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-subscriptions-id-create-invoice
  /v1/subscriptions/{id}/items:
    get:
      tags:
        - Suscripciones
      summary: Listar ítems de la suscripción
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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 de ítems.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {}
                required:
                  - data
        "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-subscriptions-id-items
    post:
      tags:
        - Suscripciones
      summary: Aplica cambios en los ítems de la suscripción
      description: "Ejecuta un lote de hasta 50 operaciones sobre los ítems: agregar, eliminar, cambiar cantidad, cambiar de precio o definir un valor unitario puntual. Las operaciones se aplican en conjunto y generan un único registro de cambio, con la factura o el crédito de prorrateo resultante."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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/SubscriptionItemsExecuteRequest"
      responses:
        "200":
          description: Cambios aplicados. `item_change_id` apunta al registro generado; `invoice_id` y `credit_id` vienen completos cuando el prorrateo generó factura o crédito.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionItemsExecuteResponse"
        "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-subscriptions-id-items
  /v1/subscriptions/{id}/sync-plan-items:
    post:
      tags:
        - Suscripciones
      summary: Resincronizar ítems con el plan actual
      description: Realinea los ítems de la suscripción con la plantilla de plan-items (reconciliación manual).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la suscripció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-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: Suscripción sincronizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionResponse"
        "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-subscriptions-id-sync-plan-items
  /v1/billing_accounts:
    get:
      tags:
        - Cuentas de Cobro
      summary: Listar cuentas de cobro
      description: Devuelve una lista paginada de las cuentas de cobro 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
            enum:
              - active
              - suspended
              - closed
            description: Filtra por estado de la cuenta de cobro.
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre.
          required: false
          name: search
          in: query
        - schema:
            type: string
            description: Filtra por el identificador externo de la cuenta.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: "Filtra por moneda ISO 4217 (ej.: `BRL`)."
          required: false
          name: currency
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Filtra por cobro automático habilitado (`true`) o deshabilitado (`false`).
          required: false
          name: auto_collection
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Filtra cuentas exentas de impuestos (`true`) o no exentas (`false`).
          required: false
          name: tax_exempt
          in: query
        - schema:
            type: string
            description: Filtra por tipo tributario del cliente.
          required: false
          name: customer_tax_type
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo mínimo de la cuenta en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: balance_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo máximo de la cuenta en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: balance_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: MRR mínimo en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: mrr_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: MRR máximo en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: mrr_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo negativo permitido mínimo en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: allowed_negative_balance_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo negativo permitido máximo en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: allowed_negative_balance_max
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra cuentas suspendidas a partir de esta fecha (formato `YYYY-MM-DD`).
            example: 2026-01-15
          required: false
          name: suspended_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra cuentas suspendidas hasta esta fecha (formato `YYYY-MM-DD`).
            example: 2026-01-15
          required: false
          name: suspended_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-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 cuentas de cobro.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountListResponse"
        "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-billing-accounts
    post:
      tags:
        - Cuentas de Cobro
      summary: Crear cuenta de cobro
      description: Crea una cuenta de cobro asociada a un cliente. El bloque `customer` localiza un cliente existente por `id`, `external_id` o `document_number`; cuando no se encuentra, crea uno nuevo (requiere `name` y `document_number`).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BillingAccountCreateRequest"
      responses:
        "201":
          description: Cuenta de cobro creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts
      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-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:
        - Cuentas de Cobro
      summary: Crear o actualizar cuenta de cobro
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BillingAccountUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountUpsertResponse"
        "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-billing-accounts
      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-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/billing_accounts/{id}:
    get:
      tags:
        - Cuentas de Cobro
      summary: Obtener cuenta de cobro
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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-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 de la cuenta de cobro.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id
    patch:
      tags:
        - Cuentas de Cobro
      summary: Actualizar cuenta de cobro
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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-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/BillingAccountUpdateRequest"
      responses:
        "200":
          description: Cuenta de cobro actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id
    delete:
      tags:
        - Cuentas de Cobro
      summary: Cerrar cuenta de cobro
      description: Cierra la cuenta de cobro (equivalente a `POST /billing_accounts/{id}/close`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: Motivo del cierre (registrado en el audit log).
          required: false
          name: reason
          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-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: Cuenta de cobro cerrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id
  /v1/billing_accounts/{id}/close:
    post:
      tags:
        - Cuentas de Cobro
      summary: Cerrar cuenta de cobro (POST /close)
      description: Cierra la cuenta de cobro. El motivo (`reason`) se registra en el audit log.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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-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/BillingAccountReasonRequest"
      responses:
        "200":
          description: Cuenta de cobro cerrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id-close
  /v1/billing_accounts/{id}/suspend:
    post:
      tags:
        - Cuentas de Cobro
      summary: Suspender cuenta de cobro
      description: Suspende la cuenta. El motivo (`reason`) se registra en el audit log.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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-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/BillingAccountReasonRequest"
      responses:
        "200":
          description: Cuenta de cobro suspendida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id-suspend
  /v1/billing_accounts/{id}/reactivate:
    post:
      tags:
        - Cuentas de Cobro
      summary: Reactivar cuenta de cobro
      description: Reactiva una cuenta de cobro suspendida.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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-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: Cuenta de cobro reactivada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BillingAccountResponse"
        "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-billing-accounts-id-reactivate
  /v1/billing_accounts/{id}/invoices:
    get:
      tags:
        - Cuentas de Cobro
      summary: Listar facturas de la cuenta
      description: Devuelve una lista paginada de las facturas de la cuenta de cobro.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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
        - 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-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 facturas.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {}
                required:
                  - data
        "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-billing-accounts-id-invoices
  /v1/billing_accounts/{id}/subscriptions:
    get:
      tags:
        - Cuentas de Cobro
      summary: Listar suscripciones de la cuenta
      description: Devuelve una lista paginada de las suscripciones de la cuenta de cobro.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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
        - 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-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 suscripciones.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {}
                required:
                  - data
        "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-billing-accounts-id-subscriptions
  /v1/billing_accounts/{id}/entitlements:
    get:
      tags:
        - Cuentas de Cobro
      summary: Listar productos contratados de la cuenta
      description: Devuelve una lista reducida de los productos a los que tiene derecho la cuenta de cobro, según las suscripciones en prueba, activas o en mora (gracia de cobro). Solo se devuelven los productos padre; los productos hijos (adicionales) se agrupan bajo el padre y se omiten. Ideal para habilitar o bloquear el uso de un producto en una app externa.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: Filtra los productos contratados por familia (grupo de productos), por ID.
          required: false
          name: product_group_id
          in: query
        - schema:
            type: string
            description: Filtra los productos contratados por familia (grupo de productos), por slug.
          required: false
          name: product_group_slug
          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-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 de productos contratados.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      billing_account_id:
                        type: string
                        format: uuid
                      entitlements:
                        type: array
                        items:
                          type: object
                          properties:
                            product_id:
                              type: string
                              format: uuid
                            product_parent_id:
                              type:
                                - string
                                - "null"
                              format: uuid
                            product_external_id:
                              type:
                                - string
                                - "null"
                            product_slug:
                              type: string
                            product_name:
                              type: string
                            product_type:
                              type: string
                            product_group_id:
                              type:
                                - string
                                - "null"
                              format: uuid
                            product_group_name:
                              type:
                                - string
                                - "null"
                            product_group_slug:
                              type:
                                - string
                                - "null"
                            quantity:
                              type: number
                            subscription_id:
                              type: string
                              format: uuid
                            subscription_status:
                              type: string
                              enum:
                                - trialing
                                - active
                                - past_due
                            current_period_end:
                              type:
                                - string
                                - "null"
                              format: date-time
                            cancel_at_period_end:
                              type: boolean
                          required:
                            - product_id
                            - product_parent_id
                            - product_external_id
                            - product_slug
                            - product_name
                            - product_type
                            - product_group_id
                            - product_group_name
                            - product_group_slug
                            - quantity
                            - subscription_id
                            - subscription_status
                            - current_period_end
                            - cancel_at_period_end
                    required:
                      - billing_account_id
                      - entitlements
                required:
                  - data
        "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-billing-accounts-id-entitlements
  /v1/billing_accounts/{id}/credits:
    get:
      tags:
        - Cuentas de Cobro
      summary: Listar créditos de la cuenta
      description: Devuelve una lista paginada de los créditos de la cuenta de cobro.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la cuenta de cobro.
          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:
              - "true"
              - "false"
            description: Incluye créditos expirados cuando es `true`.
          required: false
          name: include_expired
          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-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 créditos.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items: {}
                required:
                  - data
        "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-billing-accounts-id-credits
  /v1/customers:
    get:
      tags:
        - Clientes
      summary: Listar clientes
      description: Devuelve una lista paginada de los clientes 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 libre por nombre, documento o correo.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - natural
              - juridical
            description: "Filtra por tipo de persona: `natural` (PF) o `juridical` (PJ)."
          required: false
          name: kind
          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-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 clientes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerListResponse"
        "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-customers
    post:
      tags:
        - Clientes
      summary: Crear cliente
      description: Crea un cliente y, por defecto, una cuenta de cobro asociada. Usa `create_billing_account=false` para crear solo el cliente.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CustomerCreateRequest"
      responses:
        "201":
          description: Cliente creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerCreateResponse"
        "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-customers
      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-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:
        - Clientes
      summary: Crear o actualizar cliente
      description: "Recibe el mismo cuerpo del POST y deduplica por `id`, `public_id`, `external_id` y `document_number`, en ese orden, deteniéndose en la primera clave que encuentre un cliente. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. La actualización es parcial: los campos ausentes conservan su valor."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CustomerUpsertRequest"
      responses:
        "200":
          description: Cliente actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerUpsertResponse"
        "201":
          description: Cliente creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerUpsertResponse"
        "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-customers
      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-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/customers/{id}:
    get:
      tags:
        - Clientes
      summary: Obtener cliente
      description: El parámetro `{id}` acepta el UUID del cliente o el `external_id`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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 cliente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerResponse"
        "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-customers-id
    patch:
      tags:
        - Clientes
      summary: Actualizar cliente
      description: El parámetro `{id}` acepta el UUID del cliente o el `external_id`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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/CustomerUpdateRequest"
      responses:
        "200":
          description: Cliente actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerResponse"
        "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-customers-id
    delete:
      tags:
        - Clientes
      summary: Eliminar cliente (soft delete)
      description: Marca el cliente como eliminado sin borrar registros históricos.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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 soft delete.
          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-customers-id
  /v1/customers/{id}/statement:
    get:
      tags:
        - Clientes
      summary: Listar extracto financiero del cliente
      description: Devuelve los movimientos del extracto (facturas, pagos, aplicaciones de crédito) de la cuenta de cobro del cliente. Cuando el cliente tiene múltiples cuentas, informa `billing_account_id`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `external_id`.
          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
            format: uuid
            description: Necesario cuando el cliente tiene múltiples cuentas de cobro.
          required: false
          name: billing_account_id
          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-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 ítems del extracto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerStatementListResponse"
        "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-customers-id-statement
  /v1/customers/{id}/statement/sync:
    post:
      tags:
        - Clientes
      summary: Reconstruir el extracto a partir del historial
      description: Recrea los ítems del extracto a partir de las facturas, pagos y aplicaciones de crédito existentes. Devuelve el resumen de lo creado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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/CustomerStatementSyncRequest"
      responses:
        "200":
          description: Extracto reconstruido.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerStatementSyncResponse"
        "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-customers-id-statement-sync
  /v1/customers/{id}/recalculate-mrr:
    post:
      tags:
        - Clientes
      summary: Recalcular el MRR del cliente
      description: Recalcula el MRR (Monthly Recurring Revenue) de las cuentas de cobro del cliente a partir de las suscripciones activas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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: MRR recalculado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerRecalculateMrrResponse"
        "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-customers-id-recalculate-mrr
  /v1/customers/{id}/users:
    get:
      tags:
        - Clientes
      summary: Listar usuarios del portal del cliente
      description: Devuelve los usuarios con acceso al portal vinculados a la cuenta de cobro del cliente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `external_id`.
          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:
              - active
              - pending_verification
              - pending_invitation
              - suspended
              - locked
            description: Filtra usuarios del portal 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-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/CustomerPortalUserListResponse"
        "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-customers-id-users
    post:
      tags:
        - Clientes
      summary: Invitar usuario del portal
      description: Crea una invitación de acceso al portal para el correo informado. La invitación expira en 7 días.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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/CustomerPortalUserInviteRequest"
      responses:
        "201":
          description: Invitación creada y correo encolado para envío.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerPortalUserResponse"
        "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.
          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-customers-id-users
  /v1/customers/{id}/users/invite:
    post:
      tags:
        - Clientes
      summary: Invitar usuario del portal (verbo)
      description: Equivalente a `POST /customers/{id}/users`. Disponible como ruta de verbo para SDKs que prefieren URLs descriptivas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `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-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/CustomerPortalUserInviteRequest"
      responses:
        "201":
          description: Invitación creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerPortalUserResponse"
        "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-customers-id-users-invite
  /v1/customers/{id}/users/{user_id}:
    get:
      tags:
        - Clientes
      summary: Obtener usuario del portal
      description: El parámetro `{user_id}` acepta el UUID o el `external_id` del usuario.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `external_id`.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: user_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-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/CustomerPortalUserResponse"
        "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-customers-id-users-user-id
    patch:
      tags:
        - Clientes
      summary: Actualizar usuario del portal
      description: "Actualiza `email`, `external_id`, `sso_only` y `status`. Transiciones de estado permitidas: `active` ↔ `suspended`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `external_id`.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: user_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-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/CustomerPortalUserUpdateRequest"
      responses:
        "200":
          description: Usuario actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomerPortalUserResponse"
        "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-customers-id-users-user-id
    delete:
      tags:
        - Clientes
      summary: Eliminar usuario del portal
      description: Las invitaciones pendientes se eliminan definitivamente; los usuarios activos se suspenden.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            description: UUID del cliente o `external_id`.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: user_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-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-customers-id-users-user-id
  /v1/customers/{id}/users/{user_id}/email-preview:
    get:
      tags:
        - Clientes
      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 cliente o `external_id`.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: user_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-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/CustomerPortalUserEmailPreviewResponse"
        "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-customers-id-users-user-id-email-preview
  /v1/customers/{id}/users/{user_id}/resend:
    post:
      tags:
        - Clientes
      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 cliente o `external_id`.
          required: true
          name: id
          in: path
        - schema:
            type: string
            description: UUID del usuario del portal o su `external_id`.
          required: true
          name: user_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-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/CustomerPortalUserResendResponse"
        "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-customers-id-users-user-id-resend
  /v1/plans:
    get:
      tags:
        - Planes
      summary: Listar planes
      description: Devuelve una lista paginada de los planes 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
            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
        - schema:
            type: string
            enum:
              - draft
              - active
              - archived
            description: Filtra por estado del plan.
          required: false
          name: status
          in: query
        - schema:
            type: string
            enum:
              - standard
              - custom
              - promotional
            description: Filtra por tipo del plan.
          required: false
          name: plan_type
          in: query
        - schema:
            type: string
            enum:
              - public
              - private
            description: Filtra por visibilidad.
          required: false
          name: visibility
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por grupo de planes.
          required: false
          name: plan_group_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por empresa emisora.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra planes custom asociados a una cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Devuelve planes disponibles para la cuenta de cobro indicada (estándar + planes custom de la cuenta).
          required: false
          name: scoped_billing_account_id
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, excluye los planes de tipo `custom` de los resultados.
          required: false
          name: exclude_custom_plans
          in: query
        - schema:
            type: string
            enum:
              - monthly
              - quarterly
              - semiannual
              - annual
            description: Filtra por la periodicidad de cobro por defecto del plan.
          required: false
          name: default_billing_cycle
          in: query
        - schema:
            type: string
            description: Filtra por el identificador externo del plan.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: Filtra por el slug del plan.
          required: false
          name: slug
          in: query
        - schema:
            type: string
            description: Búsqueda de texto libre.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_before
          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-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 planes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanListResponse"
        "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-plans
    post:
      tags:
        - Planes
      summary: Crear plan
      description: Crea un plan para la organización autenticada.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanCreateRequest"
      responses:
        "201":
          description: Plan creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanResponse"
        "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-plans
      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-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:
        - Planes
      summary: Crear o actualizar plan
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanUpsertResponse"
        "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-plans
      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-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/plans/{id}:
    get:
      tags:
        - Planes
      summary: Obtener plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          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-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 plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanResponse"
        "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-plans-id
    patch:
      tags:
        - Planes
      summary: Actualizar plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          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-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/PlanUpdateRequest"
      responses:
        "200":
          description: Plan actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanResponse"
        "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-plans-id
    delete:
      tags:
        - Planes
      summary: Archivar o eliminar plan
      description: Por defecto archiva el plan (soft delete). Usa `?hard=true` para eliminar permanentemente un plan en borrador.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          required: true
          name: id
          in: path
        - schema:
            type:
              - boolean
              - "null"
            description: Cuando es `true`, elimina el plan permanentemente (solo borradores).
          required: false
          name: hard
          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-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 archivado o 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-plans-id
  /v1/plans/{id}/duplicate:
    post:
      tags:
        - Planes
      summary: Duplicar plan
      description: Crea una copia del plan (incluyendo sus ítems) en estado de borrador.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          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-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: Plan duplicado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanResponse"
        "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-plans-id-duplicate
  /v1/plans/{id}/items:
    get:
      tags:
        - Planes
      summary: Listar ítems del plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          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-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 de ítems del plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanItemListResponse"
        "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-plans-id-items
    put:
      tags:
        - Planes
      summary: Reemplazar ítems del plan
      description: Reemplaza de forma atómica todos los ítems del plan. Solo se aceptan productos raíz y cada `product_id` debe ser único en la lista.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del plan.
          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-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/PlanItemsReplaceRequest"
      responses:
        "200":
          description: Ítems del plan reemplazados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanItemsReplaceResponse"
        "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-plans-id-items
  /v1/plans/bulk-archive:
    post:
      tags:
        - Planes
      summary: Archivar planes en lote
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanBulkIdsRequest"
      responses:
        "200":
          description: Resumen del archivado en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanBulkArchiveResponse"
        "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-plans-bulk-archive
      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-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/plans/bulk-delete:
    post:
      tags:
        - Planes
      summary: Eliminar planes en lote
      description: Elimina permanentemente los planes informados. Los planes con suscripciones activas se omiten y se devuelven en `skipped_ids`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanBulkIdsRequest"
      responses:
        "200":
          description: Resumen de la eliminación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanBulkDeleteResponse"
        "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-plans-bulk-delete
      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-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/plans/bulk-move-group:
    post:
      tags:
        - Planes
      summary: Mover planes a otro grupo en lote
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanBulkMoveGroupRequest"
      responses:
        "200":
          description: Resumen del movimiento en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanBulkMoveGroupResponse"
        "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-plans-bulk-move-group
      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-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/plan_groups:
    get:
      tags:
        - Grupos de Plan
      summary: Listar grupos de planes
      description: Devuelve todos los grupos de planes de la organización actual ordenados por `display_order`.
      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 libre por nombre o slug.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, incluye grupos archivados en la lista.
          required: false
          name: include_archived
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra grupos de planes por la empresa indicada (UUID).
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve solo grupos archivados a partir de esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: archived_after
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve solo grupos archivados hasta esta fecha (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: archived_before
          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-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 de grupos de planes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupListResponse"
        "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-plan-groups
    post:
      tags:
        - Grupos de Plan
      summary: Crear grupo de planes
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanGroupCreateRequest"
      responses:
        "201":
          description: Grupo de planes creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupResponse"
        "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-plan-groups
      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-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:
        - Grupos de Plan
      summary: Crear o actualizar grupo de planes
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanGroupUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupUpsertResponse"
        "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-plan-groups
      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-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/plan_groups/{id}:
    get:
      tags:
        - Grupos de Plan
      summary: Obtener grupo de planes
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de planes.
          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-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 grupo de planes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupResponse"
        "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-plan-groups-id
    patch:
      tags:
        - Grupos de Plan
      summary: Actualizar grupo de planes
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de planes.
          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-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/PlanGroupUpdateRequest"
      responses:
        "200":
          description: Grupo de planes actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupResponse"
        "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-plan-groups-id
    delete:
      tags:
        - Grupos de Plan
      summary: Eliminar grupo de planes
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de planes.
          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-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-plan-groups-id
  /v1/plan_groups/reorder:
    post:
      tags:
        - Grupos de Plan
      summary: Reordenar grupos de planes
      description: Actualiza el `display_order` de los grupos según el orden del array `group_ids`. Todos los grupos deben pertenecer a la organización actual.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanGroupReorderRequest"
      responses:
        "200":
          description: Orden actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupReorderResponse"
        "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-plan-groups-reorder
      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-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/plan_groups/{id}/archive:
    post:
      tags:
        - Grupos de Plan
      summary: Archivar grupo de planes
      description: Marca el grupo como archivado completando `archived_at`. Los grupos archivados se ocultan de los listados por defecto.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de planes.
          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-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: Grupo de planes archivado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanGroupResponse"
        "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-plan-groups-id-archive
  /v1/products:
    get:
      tags:
        - Productos
      summary: Listar productos
      description: Devuelve una lista paginada de los productos 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
            enum:
              - all
              - draft
              - active
              - archived
            description: Filtra por estado del producto.
          required: false
          name: status
          in: query
        - schema:
            type: string
            enum:
              - public
              - private
            description: Filtra por visibilidad.
          required: false
          name: visibility
          in: query
        - schema:
            type: string
            enum:
              - base
              - addon_quantity
              - addon_fixed
              - metered
              - one_time_fixed
              - one_time_quantity
              - credits
            description: Filtra por tipo de producto.
          required: false
          name: product_type
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por grupo de productos.
          required: false
          name: product_group_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por empresa.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por producto padre.
          required: false
          name: parent_product_id
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, devuelve solo productos raíz (sin padre).
          required: false
          name: root_only
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre (nombre, slug).
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por ítem de servicio vinculado.
          required: false
          name: service_item_id
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, devuelve solo productos marcados como obligatorios.
          required: false
          name: is_required
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, devuelve solo productos que el cliente puede editar en el portal.
          required: false
          name: self_service_editable
          in: query
        - schema:
            type: string
            description: Filtra por identificador externo.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: Filtra por slug exacto del producto.
          required: false
          name: slug
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de actualización (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: updated_before
          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-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 productos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductListResponse"
        "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-products
    post:
      tags:
        - Productos
      summary: Crear producto
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductCreateRequest"
      responses:
        "201":
          description: Producto creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products
      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-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:
        - Productos
      summary: Crear o actualizar producto
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductUpsertResponse"
        "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-products
      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-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/products/{id}:
    get:
      tags:
        - Productos
      summary: Obtener producto
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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 producto.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products-id
    patch:
      tags:
        - Productos
      summary: Actualizar producto
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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/ProductUpdateRequest"
      responses:
        "200":
          description: Producto actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products-id
    delete:
      tags:
        - Productos
      summary: Archivar producto (soft delete)
      description: Archiva el producto. Devuelve 422 cuando el producto está en uso por suscripciones activas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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 soft delete.
          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-products-id
  /v1/products/{id}/archive:
    post:
      tags:
        - Productos
      summary: Archivar producto
      description: Archiva el producto. Devuelve 422 cuando el producto está en uso por suscripciones activas o ya está archivado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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: Producto archivado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products-id-archive
  /v1/products/{id}/publish:
    post:
      tags:
        - Productos
      summary: Publicar producto
      description: Promueve un producto en borrador al estado activo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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: Producto publicado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products-id-publish
  /v1/products/{id}/restore:
    post:
      tags:
        - Productos
      summary: Restaurar producto archivado
      description: Restaura un producto archivado al estado activo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del producto.
          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-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: Producto restaurado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductResponse"
        "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-products-id-restore
  /v1/products/reorder:
    post:
      tags:
        - Productos
      summary: Reordenar productos
      description: Actualiza el orden de visualización de los productos. El índice 0 del array pasa a ser el primer ítem de la lista.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductReorderRequest"
      responses:
        "200":
          description: Orden actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-reorder
      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-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:
        - Productos
      summary: Reordenar productos (PUT /reorder)
      description: Alias `PUT` para `/products/reorder`. Mismo comportamiento que la versión `POST`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductReorderRequest"
      responses:
        "200":
          description: Orden actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-reorder
      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-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/products/bulk-archive:
    post:
      tags:
        - Productos
      summary: Archivar productos en lote
      description: Archiva múltiples productos. Los IDs en uso por suscripciones activas o ya archivados se ignoran y se reportan en la respuesta.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductBulkArchiveRequest"
      responses:
        "200":
          description: Resultado de la operación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-bulk-archive
      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-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/products/bulk-delete:
    post:
      tags:
        - Productos
      summary: Eliminar productos en lote
      description: Elimina permanentemente múltiples productos. Los IDs en uso por suscripciones activas se ignoran y se reportan en la respuesta.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductBulkDeleteRequest"
      responses:
        "200":
          description: Resultado de la operación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-bulk-delete
      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-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/products/bulk-visibility:
    post:
      tags:
        - Productos
      summary: Cambiar visibilidad en lote
      description: Actualiza la visibilidad (`public` o `private`) de múltiples productos.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductBulkVisibilityRequest"
      responses:
        "200":
          description: Resultado de la operación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-bulk-visibility
      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-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/products/bulk-move-group:
    post:
      tags:
        - Productos
      summary: Mover productos a otro grupo
      description: "Mueve múltiples productos a un grupo de productos. Envía `product_group_id: null` para quitarlos del grupo actual."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductBulkMoveGroupRequest"
      responses:
        "200":
          description: Resultado de la operación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-bulk-move-group
      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-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/products/bulk-change-company:
    post:
      tags:
        - Productos
      summary: Cambiar empresa de productos en lote
      description: "Reasigna múltiples productos a otra empresa. Envía `company_id: null` para limpiar el vínculo."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductBulkChangeCompanyRequest"
      responses:
        "200":
          description: Resultado de la operación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductBulkResultResponse"
        "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-products-bulk-change-company
      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-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/product_groups:
    get:
      tags:
        - Grupos de Producto
      summary: Listar grupos de productos
      description: Devuelve una lista paginada de los grupos de productos 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 libre por el nombre del grupo.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por empresa emisora asociada.
          required: false
          name: company_id
          in: query
        - schema:
            type:
              - boolean
              - "null"
            description: "Cuando es `true`, incluye grupos archivados en el listado. Por defecto: `false`."
          required: false
          name: include_archived
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve grupos archivados a partir de esta fecha (ISO 8601).
            example: 2026-01-15
          required: false
          name: archived_after
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve grupos archivados hasta esta fecha (ISO 8601).
            example: 2026-01-15
          required: false
          name: archived_before
          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-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 grupos de productos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupListResponse"
        "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-product-groups
    post:
      tags:
        - Grupos de Producto
      summary: Crear grupo de productos
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductGroupCreateRequest"
      responses:
        "201":
          description: Grupo de productos creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupResponse"
        "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-product-groups
      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-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:
        - Grupos de Producto
      summary: Crear o actualizar grupo de productos
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductGroupUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupUpsertResponse"
        "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-product-groups
      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-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/product_groups/{id}:
    get:
      tags:
        - Grupos de Producto
      summary: Obtener grupo de productos
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de productos.
          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-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 grupo de productos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupResponse"
        "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-product-groups-id
    patch:
      tags:
        - Grupos de Producto
      summary: Actualizar grupo de productos
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de productos.
          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-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/ProductGroupUpdateRequest"
      responses:
        "200":
          description: Grupo de productos actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupResponse"
        "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-product-groups-id
    delete:
      tags:
        - Grupos de Producto
      summary: Eliminar grupo de productos
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de productos.
          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-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/ProductGroupDeletedResponse"
        "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-product-groups-id
  /v1/product_groups/{id}/archive:
    post:
      tags:
        - Grupos de Producto
      summary: Archivar grupo de productos
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de productos.
          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-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: Grupo de productos archivado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupResponse"
        "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-product-groups-id-archive
    delete:
      tags:
        - Grupos de Producto
      summary: Desarchivar grupo de productos
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del grupo de productos.
          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-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: Grupo de productos desarchivado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupResponse"
        "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-product-groups-id-archive
  /v1/product_groups/reorder:
    post:
      tags:
        - Grupos de Producto
      summary: Reordenar grupos de productos
      description: Actualiza el orden de visualización de los grupos de productos. El array `group_ids` define el nuevo orden — el índice 0 pasa a ser el primer grupo.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductGroupReorderRequest"
      responses:
        "200":
          description: Orden actualizado con éxito.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupReorderResponse"
        "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-product-groups-reorder
      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-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:
        - Grupos de Producto
      summary: Reordenar grupos de productos (alias PUT)
      description: Alias `PUT` para `POST /product_groups/reorder`. Mismo contrato.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProductGroupReorderRequest"
      responses:
        "200":
          description: Orden actualizado con éxito.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProductGroupReorderResponse"
        "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-product-groups-reorder
      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-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/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-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-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/companies:
    get:
      tags:
        - Empresas
      summary: Listar empresas
      description: Devuelve una lista paginada de las empresas (matrices y sucursales) 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
            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
        - schema:
            type: string
            enum:
              - active
              - inactive
            description: "Filtra por estado: `active` o `inactive`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Búsqueda textual por nombre, razón social, correo o documento.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Filtra solo la empresa marcada como predeterminada de la organización.
          required: false
          name: is_default
          in: query
        - schema:
            type: string
            description: Filtra sucursales por matriz. Usa el UUID de la matriz para listar sus sucursales.
          required: false
          name: parent_company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra empresas por el UUID del diseño de correo asociado.
          required: false
          name: email_layout_id
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 empresas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyListResponse"
        "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-companies
    post:
      tags:
        - Empresas
      summary: Crear empresa
      description: Crea una empresa (matriz o sucursal). Para crear una sucursal, informa `parent_company_id` — el CNPJ debe compartir el mismo prefijo que la matriz. Solo las empresas con CNPJ pueden tener sucursales. La primera empresa creada en la organización se marca como `is_default` automáticamente.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompanyCreateRequest"
      responses:
        "201":
          description: Empresa creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies
      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-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:
        - Empresas
      summary: Crear o actualizar empresa
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CompanyUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyUpsertResponse"
        "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-companies
      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-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/companies/matriz:
    get:
      tags:
        - Empresas
      summary: Listar matrices
      description: Lista las empresas matrices (sin `parent_company_id`) activas de la organización. Útil para seleccionar la matriz al crear una sucursal. Solo aparecen empresas con CNPJ.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Lista de empresas matrices.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyMatrizListResponse"
        "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-companies-matriz
      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-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/companies/{id}:
    get:
      tags:
        - Empresas
      summary: Obtener empresa
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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 de la empresa.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies-id
    patch:
      tags:
        - Empresas
      summary: Actualizar empresa
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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/CompanyUpdateRequest"
      responses:
        "200":
          description: Empresa actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies-id
    delete:
      tags:
        - Empresas
      summary: Desactivar empresa
      description: Desactiva la empresa (soft delete — equivalente a `POST /companies/{id}/deactivate`). No es posible desactivar la única empresa activa ni una empresa con suscripciones activas o en período de prueba.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Empresa desactivada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyDeleteResponse"
        "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-companies-id
  /v1/companies/{id}/set-default:
    post:
      tags:
        - Empresas
      summary: Definir empresa por defecto
      description: Marca la empresa como predeterminada de la organización. La empresa predeterminada anterior se desmarca en la misma transacción.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Empresa definida como predeterminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies-id-set-default
  /v1/companies/{id}/deactivate:
    post:
      tags:
        - Empresas
      summary: Desactivar empresa (POST /deactivate)
      description: Desactiva la empresa. No es posible desactivar la única empresa activa ni una empresa con suscripciones activas o en período de prueba. Si la empresa desactivada era la predeterminada, otra empresa activa se promueve automáticamente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Empresa desactivada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies-id-deactivate
  /v1/companies/{id}/reactivate:
    post:
      tags:
        - Empresas
      summary: Reactivar empresa
      description: Reactiva una empresa previamente desactivada. Devuelve **422** cuando la empresa ya está activa.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Empresa reactivada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyResponse"
        "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-companies-id-reactivate
  /v1/companies/{id}/fiscal:
    get:
      tags:
        - Empresas
      summary: Obtener perfil fiscal
      description: Devuelve el perfil fiscal de la empresa, o `null` cuando aún no se ha configurado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Perfil fiscal de la empresa (o `null`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyFiscalProfileResponse"
        "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-companies-id-fiscal
    patch:
      tags:
        - Empresas
      summary: Actualizar perfil fiscal
      description: Crea o actualiza (upsert) el perfil fiscal de la empresa. Incluye régimen tributario, alícuotas (ISS, PIS, COFINS, CSLL, IRPJ) y configuración de CBS/IBS.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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/CompanyFiscalProfileUpsertRequest"
      responses:
        "200":
          description: Perfil fiscal actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyFiscalProfileResponse"
        "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-companies-id-fiscal
  /v1/companies/{id}/fiscal-profile:
    get:
      tags:
        - Empresas
      summary: Obtener perfil fiscal (alias)
      description: Alias de `GET /companies/{id}/fiscal` — misma representación y comportamiento.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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: Perfil fiscal de la empresa (o `null`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyFiscalProfileResponse"
        "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-companies-id-fiscal-profile
    patch:
      tags:
        - Empresas
      summary: Actualizar perfil fiscal (alias)
      description: Alias de `PATCH /companies/{id}/fiscal` — misma representación y comportamiento.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la empresa.
          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-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/CompanyFiscalProfileUpsertRequest"
      responses:
        "200":
          description: Perfil fiscal actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CompanyFiscalProfileResponse"
        "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-companies-id-fiscal-profile
  /v1/certificates:
    get:
      tags:
        - Certificados
      summary: Listar certificados digitales
      description: Devuelve una lista paginada de los certificados digitales (A1) de la organización actual. Por seguridad, la respuesta **nunca** incluye la clave privada ni la contraseña del PFX — solo metadatos extraídos del certificado.
      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
            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
        - schema:
            type: string
            enum:
              - active
              - expired
              - revoked
              - expiring_soon
            description: Filtra por estado del certificado. `expiring_soon` devuelve certificados activos que vencen en los próximos 30 días.
          required: false
          name: status
          in: query
        - schema:
            type: string
            description: Búsqueda textual en `name`, `common_name`, `document` u `organization_name`.
          required: false
          name: search
          in: query
        - schema:
            type: string
            description: Filtra por el formato del certificado almacenado (`pfx`, `pem`).
          required: false
          name: format
          in: query
        - schema:
            type: string
            description: Filtra por el CPF o CNPJ extraído del certificado (solo dígitos).
          required: false
          name: document
          in: query
        - schema:
            type: string
            description: Filtra por el número de serie del certificado.
          required: false
          name: serial_number
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados cuya fecha de expiración (`not_after`) es mayor o igual a la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: not_after_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados cuya fecha de expiración (`not_after`) es menor o igual a la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: not_after_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados cuya fecha de inicio de validez (`not_before`) es mayor o igual a la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: not_before_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados cuya fecha de inicio de validez (`not_before`) es menor o igual a la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: not_before_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados creados a partir de la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve certificados creados hasta la fecha indicada (ISO 8601).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 certificados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CertificateListResponse"
        "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-certificates
    post:
      tags:
        - Certificados
      summary: Subir certificado digital
      description: |-
        Sube un certificado digital A1 vía `multipart/form-data`. La clave privada y la contraseña se cifran en reposo y **nunca** son devueltas por la API. El endpoint detecta duplicados por `thumbprint` y asocia automáticamente el certificado a un `person` por el CNPJ/CPF extraído.

        Valores aceptados para `type`:
        - `pfx` — enviar `file` (PFX/P12 binario) y `password`.
        - `cert_key` — enviar `cert_file` (PEM del certificado) y `key_file` (PEM de la clave).
        - `combined_pem` — enviar `file` (PEM con certificado + clave).
        - `cert_key_password` — enviar `cert_file`, `key_file` y `password` (clave protegida por contraseña).
      security:
        - bearerAuth: []
      requestBody:
        content:
          multipart/form-data:
            schema:
              $ref: "#/components/schemas/CertificateUploadRequest"
      responses:
        "201":
          description: Certificado subido y almacenado con éxito.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CertificateResponse"
        "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-certificates
      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-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/certificates/{id}:
    get:
      tags:
        - Certificados
      summary: Obtener certificado
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del certificado.
          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-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 certificado (sin datos sensibles).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CertificateResponse"
        "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-certificates-id
    delete:
      tags:
        - Certificados
      summary: Eliminar certificado
      description: Elimina el certificado mediante **soft delete**. Los datos cifrados permanecen en la base solo para fines de auditoría.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del certificado.
          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-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: Certificado 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-certificates-id
  /v1/coupons:
    get:
      tags:
        - Cupones
      summary: Listar cupones
      description: Devuelve una lista paginada de los cupones 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
            enum:
              - "true"
              - "false"
            description: "Filtra por estado: `true` devuelve solo cupones activos; `false`, solo inactivos."
          required: false
          name: is_active
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre en `code` y `name`.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - percentage
              - fixed_amount
            description: "Filtra por tipo de descuento: `percentage` o `fixed_amount`."
          required: false
          name: discount_type
          in: query
        - schema:
            type: string
            description: Filtra por el código exacto del cupón.
          required: false
          name: code
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Valor mínimo de `min_purchase` (en BRL) para filtrar cupones.
            example: 100
          required: false
          name: min_purchase_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Valor máximo de `min_purchase` (en BRL) para filtrar cupones.
            example: 100
          required: false
          name: min_purchase_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Valor mínimo de `max_discount` (en BRL) para filtrar cupones.
            example: 100
          required: false
          name: max_discount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Valor máximo de `max_discount` (en BRL) para filtrar cupones.
            example: 100
          required: false
          name: max_discount_max
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones cuya fecha de inicio de validez es igual o posterior a esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: valid_from_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones cuya fecha de inicio de validez es igual o anterior a esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: valid_from_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones cuya fecha de expiración es igual o posterior a esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: valid_until_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones cuya fecha de expiración es igual o anterior a esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: valid_until_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones creados a partir de esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve cupones creados hasta esta fecha (AAAA-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 cupones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponListResponse"
        "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-coupons
    post:
      tags:
        - Cupones
      summary: Crear cupón
      description: Crea un cupón de descuento. El `code` debe ser único por organización. Usa `discount_type=percentage` con `discount_value` entre `0` y `100`, o `discount_type=fixed_amount` con `discount_value` en BRL (float, hasta 4 decimales).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CouponCreateRequest"
      responses:
        "201":
          description: Cupón creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponResponse"
        "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-coupons
      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-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:
        - Cupones
      summary: Crear o actualizar cupón
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CouponUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponUpsertResponse"
        "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-coupons
      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-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/coupons/{id}:
    get:
      tags:
        - Cupones
      summary: Obtener cupón
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cupó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-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 cupón.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponResponse"
        "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-coupons-id
    patch:
      tags:
        - Cupones
      summary: Actualizar cupón
      description: Actualiza campos editables del cupón. `code`, `discount_type`, `discount_value` y `currency` son inmutables después de la creación.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cupó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-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/CouponUpdateRequest"
      responses:
        "200":
          description: Cupón actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponResponse"
        "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-coupons-id
    delete:
      tags:
        - Cupones
      summary: Eliminar cupón
      description: Elimina el cupón permanentemente. Solo se permite mientras el cupón **no tenga canjes registrados** — de lo contrario, usa `POST /coupons/{id}/deactivate` para preservar el historial.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cupó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-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: Cupón 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: 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-coupons-id
  /v1/coupons/{id}/deactivate:
    post:
      tags:
        - Cupones
      summary: Desactivar cupón
      description: "Desactiva el cupón: los nuevos canjes quedan bloqueados, pero los canjes anteriores se preservan."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cupó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-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: Cupón desactivado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponResponse"
        "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-coupons-id-deactivate
  /v1/coupons/{id}/redemptions:
    get:
      tags:
        - Cupones
      summary: Listar canjes del cupón
      description: Devuelve una lista paginada de los canjes registrados para el cupón.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cupón.
          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
        - 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-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 canjes del cupón.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CouponRedemptionListResponse"
        "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-coupons-id-redemptions
  /v1/credits:
    get:
      tags:
        - Créditos
      summary: Listar créditos
      description: Devuelve una lista paginada de los créditos de la organización actual. Por defecto, los créditos expirados se omiten — usa `usage` o `include_expired` para incluirlos.
      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
            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
        - schema:
            type: string
            format: uuid
            description: Filtra créditos por cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra créditos por la `company` vinculada.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            enum:
              - promotional
              - adjustment
              - refund
              - manual
            description: "Filtra por tipo de crédito: `promotional`, `adjustment`, `refund` o `manual`."
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - available
              - used
              - expired
            description: Filtra por estado de uso — `available` (saldo restante y no expirado), `used` (consumido por completo) o `expired` (vencido).
          required: false
          name: usage
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Incluye créditos expirados cuando es `true`. Se ignora si se informa `usage`.
          required: false
          name: include_expired
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo del crédito en BRL (inclusivo).
            example: 100
          required: false
          name: amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo del crédito en BRL (inclusivo).
            example: 100
          required: false
          name: amount_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo restante mínimo en BRL (inclusivo).
            example: 100
          required: false
          name: amount_remaining_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Saldo restante máximo en BRL (inclusivo).
            example: 100
          required: false
          name: amount_remaining_max
          in: query
        - schema:
            type: string
            format: date
            description: Límite inferior de `expires_at` (YYYY-MM-DD, inclusivo).
            example: 2026-01-15
          required: false
          name: expires_after
          in: query
        - schema:
            type: string
            format: date
            description: Límite superior de `expires_at` (YYYY-MM-DD, inclusivo).
            example: 2026-01-15
          required: false
          name: expires_before
          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-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 créditos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditListResponse"
        "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-credits
    post:
      tags:
        - Créditos
      summary: Agregar crédito
      description: Agrega un crédito a una cuenta de cobro. El monto se acredita en `balance` de la `BillingAccount` y queda disponible para descontar facturas futuras. Cuando se informa `company_id`, el crédito solo puede aplicarse a facturas de la misma `company`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditCreateRequest"
      responses:
        "201":
          description: Crédito creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditResponse"
        "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-credits
      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-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:
        - Créditos
      summary: Crear o actualizar crédito
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditUpsertResponse"
        "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-credits
      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-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/credits/{id}:
    get:
      tags:
        - Créditos
      summary: Obtener crédito
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del crédito.
          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-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 crédito.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditResponse"
        "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-credits-id
    patch:
      tags:
        - Créditos
      summary: Actualizar crédito
      description: Ajusta el crédito (tipo, monto, descripción o fecha de expiración). `amount` solo puede cambiarse si el crédito no ha sido parcialmente utilizado — de lo contrario la API responde `400`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del crédito.
          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-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/CreditUpdateRequest"
      responses:
        "200":
          description: Crédito actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditResponse"
        "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-credits-id
    delete:
      tags:
        - Créditos
      summary: Eliminar crédito
      description: Elimina el crédito y revierte el saldo correspondiente en la cuenta de cobro. Solo se permite si no se ha consumido ningún centavo del crédito — de lo contrario la API responde `400`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del crédito.
          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-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: Crédito eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditDeleteResponse"
        "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: delete-credits-id
  /v1/invoices:
    get:
      tags:
        - Facturas
      summary: Listar facturas
      description: Devuelve una lista paginada de las facturas 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
            enum:
              - draft
              - open
              - paid
              - void
              - uncollectible
            description: "Filtra por estado: `draft`, `open`, `paid`, `void` o `uncollectible`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `billing_account_id`.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `company_id` emisor.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `subscription_id` de origen.
          required: false
          name: subscription_id
          in: query
        - schema:
            type: string
            description: Filtra por `due_date` inicial (inclusive).
          required: false
          name: due_date_from
          in: query
        - schema:
            type: string
            description: Filtra por `due_date` final (inclusive).
          required: false
          name: due_date_to
          in: query
        - schema:
            type: string
            description: Filtra por `created_at` inicial (inclusive).
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            description: Filtra por `created_at` final (inclusive).
          required: false
          name: date_to
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre.
          required: false
          name: search
          in: query
        - schema:
            type:
              - number
              - "null"
            description: Filtra por valor total mínimo, en BRL (float, hasta 4 decimales).
          required: false
          name: total_min
          in: query
        - schema:
            type:
              - number
              - "null"
            description: Filtra por valor total máximo, en BRL (float, hasta 4 decimales).
          required: false
          name: total_max
          in: query
        - schema:
            type: string
            description: Filtra por CPF/CNPJ del cliente.
          required: false
          name: document_number
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, devuelve solo facturas sin pagos asociados.
          required: false
          name: without_payments
          in: query
        - schema:
            type: string
            enum:
              - all
              - with_plan
              - without_plan
            description: "Filtra por origen: `all`, `with_plan` (con suscripción) o `without_plan` (suelta)."
          required: false
          name: plan_filter
          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-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 facturas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceListResponse"
        "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-invoices
    post:
      tags:
        - Facturas
      summary: Crear factura
      description: Crea una factura para una cuenta de cobro. Acepta ítems de línea, parcelas opcionales (`installments`, mínimo 2) y política de emisión de NF-e.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoiceCreateRequest"
      responses:
        "201":
          description: Factura creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices
      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-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:
        - Facturas
      summary: Crear o actualizar factura
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InvoiceUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceUpsertResponse"
        "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-invoices
      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-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/invoices/pending-payment:
    get:
      tags:
        - Facturas
      summary: Listar facturas con pago pendiente
      description: Devuelve facturas finalizadas (`status = open`) cuya `due_date` ya pasó.
      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
            format: uuid
            description: Filtra por `billing_account_id`.
          required: false
          name: billing_account_id
          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-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 facturas con pago pendiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceListResponse"
        "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-invoices-pending-payment
  /v1/invoices/pending-nfe:
    get:
      tags:
        - Facturas
      summary: Listar facturas con NF-e pendiente
      description: Devuelve facturas pagadas pero con emisión de NF-e pendiente — sin NF-e, o con NF-e en estado `pending`, `processing` o `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
            format: uuid
            description: Filtra por `billing_account_id`.
          required: false
          name: billing_account_id
          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-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 facturas con NF-e pendiente.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceListResponse"
        "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-invoices-pending-nfe
  /v1/invoices/{id}:
    get:
      tags:
        - Facturas
      summary: Obtener factura
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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 de la factura.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id
    patch:
      tags:
        - Facturas
      summary: Actualizar factura
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoiceUpdateRequest"
      responses:
        "200":
          description: Factura actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id
    delete:
      tags:
        - Facturas
      summary: Eliminar factura
      description: Elimina una factura en borrador (`draft`). Las facturas finalizadas deben cancelarse vía `POST /invoices/{id}/void`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: Factura eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceDeletedResponse"
        "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-invoices-id
  /v1/invoices/{id}/finalize:
    post:
      tags:
        - Facturas
      summary: Finalizar factura
      description: Finaliza una factura en borrador (`draft` → `open`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: Factura finalizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id-finalize
  /v1/invoices/{id}/void:
    post:
      tags:
        - Facturas
      summary: Cancelar (void) factura
      description: Cancela una factura abierta (`open` → `void`). El motivo (`reason`) se registra en el audit log.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoiceVoidRequest"
      responses:
        "200":
          description: Factura cancelada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id-void
  /v1/invoices/{id}/undo-payment:
    post:
      tags:
        - Facturas
      summary: Deshacer pago de la factura
      description: Revierte el pago de la factura (`paid` → `open`). El motivo (`reason`) se registra en el audit log.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoiceUndoPaymentRequest"
      responses:
        "200":
          description: Pago deshecho.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id-undo-payment
  /v1/invoices/{id}/pay:
    post:
      tags:
        - Facturas
      summary: Pagar factura
      description: "Dos modos: (a) cuando se informa `payment_method`, crea un pago vía gateway (`pix`, `bank_slip` o `card`) y devuelve los artefactos del método (QR code, código de barras o estado de la tarjeta) — o, con `bank_transfer`, un cobro por transferencia a la cuenta bancaria (`bank_account_id`) o clave Pix (`pix_key_id`) de la organización, sin gateway, devolviendo los datos en `bank_transfer` y quedando pendiente hasta la baja manual; (b) cuando se omite, marca la factura como pagada manualmente (reconciliación)."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoicePayRequest"
      responses:
        "200":
          description: Resultado del pago o factura marcada como pagada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoicePayResponse"
        "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-invoices-id-pay
  /v1/invoices/{id}/send-reminder:
    post:
      tags:
        - Facturas
      summary: Enviar recordatorio de cobro
      description: Envía por correo un recordatorio de cobro de la factura al `billing_email` de la cuenta.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: Recordatorio enviado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-invoices-id-send-reminder
  /v1/invoices/{id}/issue-nfe:
    post:
      tags:
        - Facturas
      summary: Emitir NF-e para la factura
      description: Dispara la emisión de la NF-e (Factura Electrónica) para la factura.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: NF-e en cola/emitida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceNfeResponse"
        "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-invoices-id-issue-nfe
  /v1/invoices/{id}/apply-credits:
    post:
      tags:
        - Facturas
      summary: Aplicar créditos a la factura
      description: Aplica créditos de la cuenta de cobro en una factura abierta (`status = open`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoiceApplyCreditsRequest"
      responses:
        "200":
          description: Créditos aplicados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceCreditsResponse"
        "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-invoices-id-apply-credits
  /v1/invoices/{id}/remove-credits:
    post:
      tags:
        - Facturas
      summary: Eliminar créditos aplicados
      description: Elimina todos los créditos aplicados a la factura, devolviéndolos a la cuenta de cobro. Solo funciona en facturas abiertas (`status = open`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: Créditos eliminados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceCreditsResponse"
        "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-invoices-id-remove-credits
  /v1/invoices/{id}/pdf:
    get:
      tags:
        - Facturas
      summary: Descargar PDF de la factura
      description: Genera y descarga el PDF de la factura como adjunto binario (`application/pdf`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: PDF de la factura.
          content:
            application/pdf:
              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-invoices-id-pdf
  /v1/invoices/{id}/payment-methods:
    get:
      tags:
        - Facturas
      summary: Listar métodos de pago disponibles
      description: Lista los métodos de pago disponibles para pagar esta factura, según los gateways activos de la organización y la configuración del portal.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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: Métodos de pago disponibles.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoicePaymentMethodsResponse"
        "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-invoices-id-payment-methods
  /v1/invoices/{id}/installments:
    get:
      tags:
        - Facturas
      summary: Listar parcelas de la factura
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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 de parcelas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceInstallmentsListResponse"
        "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-invoices-id-installments
    post:
      tags:
        - Facturas
      summary: Crear/actualizar cronograma de parcelas
      description: Crea o reemplaza el cronograma de parcelas de la factura. Mínimo de 2 parcelas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          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-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/InvoiceInstallmentsCreateRequest"
      responses:
        "201":
          description: Cronograma de parcelas creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceInstallmentsListResponse"
        "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-invoices-id-installments
  /v1/invoices/{id}/installments/{installment_id}/mark-paid:
    post:
      tags:
        - Facturas
      summary: Marcar parcela como pagada
      description: Marca manualmente una parcela como pagada (reconciliación, sin llamada al gateway).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID de la parcela.
          required: true
          name: installment_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-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: Parcela marcada como pagada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceInstallmentResponse"
        "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-invoices-id-installments-installment-id-mark-paid
  /v1/invoices/{id}/installments/{installment_id}/pay:
    post:
      tags:
        - Facturas
      summary: Pagar parcela
      description: Procesa el pago de una parcela vía gateway. La parcela anterior debe estar pagada.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la factura.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID de la parcela.
          required: true
          name: installment_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-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/InvoiceInstallmentPayRequest"
      responses:
        "200":
          description: Resultado del pago de la parcela.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoicePayResponse"
        "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-invoices-id-installments-installment-id-pay
  /v1/payments:
    get:
      tags:
        - Pagos
      summary: Listar pagos
      description: Devuelve una lista paginada de los pagos 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
            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
        - schema:
            type: string
            enum:
              - pending
              - processing
              - succeeded
              - failed
              - canceled
              - partial
              - refunded
              - partially_refunded
            description: Filtra por estado del pago.
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los pagos de una factura específica.
          required: false
          name: invoice_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los pagos de una cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los pagos de una empresa específica.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los pagos procesados por un gateway específico.
          required: false
          name: gateway_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los pagos de un medio de pago específico.
          required: false
          name: payment_method_id
          in: query
        - schema:
            type: string
            enum:
              - card
              - bank_slip
              - pix
              - bank_transfer
            description: "Filtra por medio de pago: `card`, `bank_slip`, `pix` o `bank_transfer`."
          required: false
          name: payment_method_type
          in: query
        - schema:
            type: string
            description: Filtra por ID externo (campo libre para identificadores del sistema legado).
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: Filtra por el identificador del pago en el gateway upstream.
          required: false
          name: gateway_payment_id
          in: query
        - schema:
            type: string
            enum:
              - all
              - with_invoice
              - without_invoice
            description: "Filtra por presencia de factura: `all`, `with_invoice` o `without_invoice`."
          required: false
          name: invoice_filter
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre.
          required: false
          name: search
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo cobrado (en BRL).
            example: 100
          required: false
          name: amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo cobrado (en BRL).
            example: 100
          required: false
          name: amount_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo efectivamente recibido (en BRL).
            example: 100
          required: false
          name: paid_amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo efectivamente recibido (en BRL).
            example: 100
          required: false
          name: paid_amount_max
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Fecha inicial de confirmación del pago — formato ISO 8601.
            example: 2026-01-15
          required: false
          name: paid_after
          in: query
        - schema:
            type: string
            format: date
            description: Fecha final de confirmación del pago — formato ISO 8601.
            example: 2026-01-15
          required: false
          name: paid_before
          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-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 pagos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentListResponse"
        "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-payments
    post:
      tags:
        - Pagos
      summary: Procesar pago
      description: Procesa un pago para una factura existente. Acepta un `payment_method_id` previamente registrado **o** un bloque `payment_method` con datos de tarjeta/PIX/boleto. Cuando se omite `amount`, cobra el saldo abierto de la factura.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentCreateRequest"
      responses:
        "201":
          description: Pago creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments
      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-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/payments/bulk-update-invoice:
    post:
      tags:
        - Pagos
      summary: Reasignar pagos a otra factura
      description: Actualiza en bloque la factura asociada a los pagos indicados. Útil para corregir vínculos cuando los pagos llegaron apuntando a la factura equivocada.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentBulkUpdateInvoiceRequest"
      responses:
        "200":
          description: Pagos reasignados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentBulkUpdateInvoiceResponse"
        "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-payments-bulk-update-invoice
      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-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/payments/{id}:
    get:
      tags:
        - Pagos
      summary: Obtener pago
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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 pago.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id
    delete:
      tags:
        - Pagos
      summary: Eliminar pago
      description: Elimina un pago. Los pagos ya confirmados no pueden eliminarse — use `cancel` o `refund`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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: Pago eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentDeletedResponse"
        "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-payments-id
  /v1/payments/{id}/cancel:
    post:
      tags:
        - Pagos
      summary: Cancelar pago
      description: Cancela un pago abierto. Cuando `cancel_on_gateway` es `true` (por defecto), la cancelación se propaga al gateway.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentCancelRequest"
      responses:
        "200":
          description: Pago cancelado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id-cancel
  /v1/payments/{id}/retry:
    post:
      tags:
        - Pagos
      summary: Reintentar pago
      description: Reprocesa un pago fallido. Opcionalmente cambia a una tarjeta nueva (vía `card`) o a un medio de pago guardado (`payment_method_id`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentRetryRequest"
      responses:
        "200":
          description: Pago reprocesado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id-retry
  /v1/payments/{id}/change-card:
    post:
      tags:
        - Pagos
      summary: Cambiar tarjeta del pago
      description: Reemplaza la tarjeta de crédito de un pago fallido procesado por Pagar.me. La nueva tarjeta debe estar registrada previamente en `payment_methods`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentChangeCardRequest"
      responses:
        "200":
          description: Tarjeta cambiada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id-change-card
  /v1/payments/{id}/change-due-date:
    post:
      tags:
        - Pagos
      summary: Cambiar vencimiento del boleto
      description: Cambia el vencimiento de un pago en boleto pendiente emitido vía gateway Kobana. La nueva fecha debe ser futura.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentChangeDueDateRequest"
      responses:
        "200":
          description: Vencimiento actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentChangeDueDateResponse"
        "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-payments-id-change-due-date
  /v1/payments/{id}/send-email:
    post:
      tags:
        - Pagos
      summary: Enviar boleto por correo
      description: Envía el enlace del boleto por correo al destinatario indicado. Disponible solo para pagos en boleto pendientes.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentSendEmailRequest"
      responses:
        "200":
          description: Correo enviado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentSendEmailResponse"
        "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-payments-id-send-email
  /v1/payments/{id}/sync:
    post:
      tags:
        - Pagos
      summary: Sincronizar pago con el gateway
      description: Sincroniza el estado del pago con el gateway upstream (PIX/boleto Kobana o reembolso Pagar.me). Devuelve el pago actualizado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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: Pago sincronizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id-sync
  /v1/payments/{id}/refund:
    post:
      tags:
        - Pagos
      summary: Reembolsar pago
      description: Reembolsa un pago exitoso. Sin `amount`, reembolsa el monto total; con un monto parcial, emite un reembolso parcial.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del pago.
          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-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/PaymentRefundRequest"
      responses:
        "200":
          description: Pago reembolsado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentResponse"
        "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-payments-id-refund
  /v1/payment_methods:
    get:
      tags:
        - Métodos de Pago
      summary: Listar métodos de pago
      description: "Devuelve una lista paginada de los métodos de pago de la organización actual. Filtros opcionales: `billing_account_id`, `type`, `status`."
      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
            format: uuid
            description: Filtra por UUID de la cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            enum:
              - card
              - bank_slip
              - pix
              - bank_transfer
            description: "Filtra por tipo: `card`, `bank_slip`, `pix` o `bank_transfer`."
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - active
              - expired
              - failed
            description: "Filtra por estado: `active`, `expired` 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-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 métodos de pago.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodListResponse"
        "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-payment-methods
    post:
      tags:
        - Métodos de Pago
      summary: Crear método de pago
      description: Crea un método de pago asociado a una cuenta de cobro. Para `type=card`, envía el bloque `card` con el `card_token` generado por la tokenización del lado del cliente. Para `type=bank_transfer`, envía el bloque `bank_account`. Para `bank_slip` y `pix`, basta con el `type` — el gateway predeterminado se resuelve por la organización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentMethodCreateRequest"
      responses:
        "201":
          description: Método de pago creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodResponse"
        "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-payment-methods
      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-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:
        - Métodos de Pago
      summary: Crear o actualizar forma de pago
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentMethodUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodUpsertResponse"
        "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-payment-methods
      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-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/payment_methods/{id}:
    get:
      tags:
        - Métodos de Pago
      summary: Obtener método de pago
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del método de pago.
          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-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 método de pago.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodResponse"
        "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-payment-methods-id
    patch:
      tags:
        - Métodos de Pago
      summary: Actualizar vencimiento de la tarjeta
      description: Actualiza solo el mes y año de vencimiento de la tarjeta asociada al método. Falla cuando `type` no es `card`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del método de pago.
          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-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/PaymentMethodUpdateRequest"
      responses:
        "200":
          description: Método de pago actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodResponse"
        "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-payment-methods-id
    delete:
      tags:
        - Métodos de Pago
      summary: Eliminar método de pago
      description: Soft delete del método de pago (lo marca como `removed`). Falla cuando hay pagos pendientes o en procesamiento. Si era el predeterminado, otro método activo se promueve automáticamente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del método de pago.
          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-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: Método de pago eliminado.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      deleted:
                        type: boolean
                    required:
                      - deleted
                required:
                  - data
        "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-payment-methods-id
  /v1/payment_methods/{id}/set-default:
    post:
      tags:
        - Métodos de Pago
      summary: Definir método como predeterminado
      description: Marca el método como predeterminado de la cuenta de cobro y desmarca los anteriores. Falla cuando el método no está `active`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del método de pago.
          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-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: Método de pago definido como predeterminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PaymentMethodResponse"
        "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-payment-methods-id-set-default
  /v1/nfes:
    get:
      tags:
        - NF-e
      summary: Listar NF-e
      description: Devuelve una lista paginada de NF-e (facturas electrónicas) 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
            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
        - schema:
            type: string
            format: uuid
            description: Filtra por `billing_account_id`.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `company_id` emisor.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `invoice_id` vinculado.
          required: false
          name: invoice_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `payment_id` vinculado.
          required: false
          name: payment_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `transaction_id` vinculado.
          required: false
          name: transaction_id
          in: query
        - schema:
            type: string
            enum:
              - draft
              - pending
              - processing
              - issued
              - pending_cancel
              - canceling
              - canceled
              - error
            description: "Filtra por estado: `draft`, `pending`, `processing`, `issued`, `pending_cancel`, `canceling`, `canceled` o `error`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            enum:
              - with
              - without
            description: "Filtra por presencia de factura: `with` (solo con factura) o `without` (solo sueltas)."
          required: false
          name: invoice_filter
          in: query
        - schema:
            type:
              - integer
              - "null"
            description: Filtra por número de la NF-e.
          required: false
          name: nfe_number
          in: query
        - schema:
            type: string
            description: Filtra por serie de la NF-e.
          required: false
          name: nfe_series
          in: query
        - schema:
            type: string
            description: Filtra por clave de acceso de la NF-e.
          required: false
          name: nfe_key
          in: query
        - schema:
            type: string
            description: Filtra por identificador externo de la NF-e.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: Filtra por código LC 116.
          required: false
          name: lc116_code
          in: query
        - schema:
            type: string
            description: Filtra por código del servicio municipal.
          required: false
          name: service_code
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo de la NF-e en reales (filtra `amount`).
            example: 100
          required: false
          name: amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo de la NF-e en reales (filtra `amount`).
            example: 100
          required: false
          name: amount_max
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `issue_date` inicial (inclusivo, formato YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: issue_date_from
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `issue_date` final (inclusivo, formato YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: issue_date_to
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `cancelled_at` inicial (inclusivo, formato YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: cancelled_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `cancelled_at` final (inclusivo, formato YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: cancelled_before
          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-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 NF-e.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeListResponse"
        "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-nfes
    post:
      tags:
        - NF-e
      summary: Crear NF-e (borrador)
      description: Crea una NF-e en borrador (`draft`) para emisión posterior vía `POST /nfes/{id}/issue`. Acepta datos del tomador (`customer`) y alícuotas opcionales.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeCreateRequest"
      responses:
        "201":
          description: NF-e creada en borrador.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes
      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-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:
        - NF-e
      summary: Crear o actualizar NF-e
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeUpsertResponse"
        "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-nfes
      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-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/nfes/sync:
    post:
      tags:
        - NF-e
      summary: Sincronizar NF-e de la organización
      description: Dispara un job en background para sincronizar todas las NF-e de la organización con el proveedor (actualiza estado, descarga PDFs/XMLs pendientes). Devuelve el `job_id` para seguimiento. Rechaza si ya hay una sync activa.
      security:
        - bearerAuth: []
      responses:
        "201":
          description: Sync en cola.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeSyncOrgResponse"
        "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-nfes-sync
      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-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/nfes/bulk:
    post:
      tags:
        - NF-e
      summary: Actualizar NF-e en lote
      description: Actualiza varias NF-e a la vez. Hoy soporta vincular o desvincular una factura (`invoice_id`) en hasta 100 NF-e por solicitud.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeBulkUpdateRequest"
      responses:
        "200":
          description: Cantidad de NF-e actualizadas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeBulkUpdateResponse"
        "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-nfes-bulk
      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-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/nfes/bulk-delete:
    post:
      tags:
        - NF-e
      summary: Eliminar NF-e en lote
      description: Elimina hasta 100 NF-e a la vez. Todas deben estar en estado `draft` y pertenecer a la organización actual.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeBulkDeleteRequest"
      responses:
        "200":
          description: Cantidad de NF-e eliminadas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeBulkDeleteResponse"
        "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-nfes-bulk-delete
      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-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/nfes/request-tries:
    get:
      tags:
        - NF-e
      summary: Listar reintentos de solicitud (organización)
      description: Lista todos los intentos de solicitud al proveedor de NF-e de la organización, paginados y ordenados por fecha descendente.
      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-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 intentos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeRequestTryPaginatedResponse"
        "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-nfes-request-tries
  /v1/nfes/fetch-from-sefaz:
    post:
      tags:
        - NF-e
      summary: Buscar NFS-e en ADN (SEFAZ)
      description: Busca una NFS-e en el Ambiente de Dados Nacional (ADN) usando una clave de acceso de 50 dígitos y un certificado digital previamente registrado (autenticación mTLS).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeFetchFromSefazRequest"
      responses:
        "200":
          description: Resultado de la búsqueda en el ADN.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeFetchFromSefazResponse"
        "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-nfes-fetch-from-sefaz
      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-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/nfes/fetch-barueri:
    post:
      tags:
        - NF-e
      summary: Buscar NFS-e en Barueri
      description: Busca una NFS-e en el endpoint municipal de Barueri usando el `codigo_autenticidade` impreso en el DANFSE y el CPF/CNPJ del tomador. Devuelve el XML crudo y, cuando se encuentra, la NF-e ya existente en la organización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeFetchBarueriRequest"
      responses:
        "200":
          description: Resultado de la búsqueda con XML y referencia a la NF-e existente, cuando exista.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeFetchBarueriResponse"
        "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-nfes-fetch-barueri
      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-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/nfes/import-barueri:
    post:
      tags:
        - NF-e
      summary: Importar NFS-e Barueri
      description: Importa una NFS-e de Barueri en la base de datos. Acepta un XML crudo (devuelto por `POST /nfes/fetch-barueri`) o el `codigo_autenticidade` + `cnpj_tomador` para re-buscar antes de importar. Crea la `BillingAccount` del tomador cuando aún no existe.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NfeImportBarueriRequest"
      responses:
        "200":
          description: Resultado de la importación con flags `created`/`updated` y la NF-e persistida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeImportBarueriResponse"
        "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-nfes-import-barueri
      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-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/nfes/{id}:
    get:
      tags:
        - NF-e
      summary: Obtener NF-e
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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 de la NF-e.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id
    patch:
      tags:
        - NF-e
      summary: Actualizar NF-e (borrador)
      description: Actualiza campos de la NF-e. Solo NF-e en `draft` aceptan cambios en montos y códigos fiscales.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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/NfeUpdateRequest"
      responses:
        "200":
          description: NF-e actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id
    delete:
      tags:
        - NF-e
      summary: Eliminar NF-e
      description: Elimina una NF-e. Permitido solo para estados `draft`, `pending`, `processing`, `error` o `canceled`. NF-e `issued` deben cancelarse vía `POST /nfes/{id}/cancel`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: NF-e eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeDeletedResponse"
        "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-nfes-id
  /v1/nfes/{id}/issue:
    post:
      tags:
        - NF-e
      summary: Emitir NF-e
      description: Emite una NF-e en borrador (`draft`) o reintenta una NF-e en `pending`/`error`. Envía la solicitud al proveedor configurado en la organización.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: NF-e en cola/emitida.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id-issue
  /v1/nfes/{id}/cancel:
    post:
      tags:
        - NF-e
      summary: Cancelar NF-e
      description: Cancela una NF-e emitida. Encola la cancelación de forma asíncrona con el proveedor. El `reason` debe tener al menos 15 caracteres y se registra en el audit log.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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/NfeCancelRequest"
      responses:
        "200":
          description: Cancelación en cola.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id-cancel
  /v1/nfes/{id}/retry-cancel:
    post:
      tags:
        - NF-e
      summary: Reintentar cancelación de la NF-e
      description: Reintenta la cancelación de una NF-e atascada en `pending_cancel`, `canceling` o `error`. Re-encola el job de cancelación.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: Reintento de cancelación en cola.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id-retry-cancel
  /v1/nfes/{id}/sync:
    post:
      tags:
        - NF-e
      summary: Sincronizar PDF/XML de la NF-e
      description: Descarga del proveedor el PDF y el XML de la NF-e y los persiste en la base de datos.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: PDF/XML sincronizados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeResponse"
        "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-nfes-id-sync
  /v1/nfes/{id}/pdf:
    get:
      tags:
        - NF-e
      summary: Descargar PDF de la NF-e
      description: Descarga el PDF de la NF-e (DANFE) como adjunto binario (`application/pdf`). Servido desde la base de datos cuando está disponible; en caso contrario, se busca en el proveedor.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: PDF de la NF-e.
          content:
            application/pdf:
              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-nfes-id-pdf
  /v1/nfes/{id}/xml:
    get:
      tags:
        - NF-e
      summary: Descargar XML de la NF-e
      description: Descarga el XML de la NF-e como adjunto binario (`application/xml`). Servido desde la base de datos cuando está disponible; en caso contrario, se busca en el proveedor.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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: XML de la NF-e.
          content:
            application/xml:
              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-nfes-id-xml
  /v1/nfes/{id}/request-tries:
    get:
      tags:
        - NF-e
      summary: Listar reintentos de solicitud de la NF-e
      description: Lista los intentos (`NfeRequestTry`) realizados al proveedor para esta NF-e — una entrada por llamada, con endpoint, estado HTTP, duración y mensajes de error.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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 de intentos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeRequestTryListResponse"
        "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-nfes-id-request-tries
  /v1/nfes/{id}/requests:
    get:
      tags:
        - NF-e
      summary: Listar solicitudes externas de la NF-e
      description: Lista las solicitudes HTTP capturadas para esta NF-e (llamadas al proveedor y webhooks recibidos), con paginación. Usa `direction` para filtrar entre `outbound` e `inbound`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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:
              - outbound
              - inbound
            description: "Filtra solicitudes por dirección: `outbound` (llamadas salientes) o `inbound` (webhooks recibidos)."
          required: false
          name: direction
          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-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 solicitudes.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeExternalRequestListResponse"
        "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-nfes-id-requests
  /v1/nfes/{id}/requests/{request_id}:
    get:
      tags:
        - NF-e
      summary: Obtener solicitud externa
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID de la solicitud externa.
          required: true
          name: request_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-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 de la solicitud externa, incluyendo cabeceras y cuerpos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeExternalRequestResponse"
        "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-nfes-id-requests-request-id
  /v1/nfes/{id}/validate-barueri:
    post:
      tags:
        - NF-e
      summary: Validar NFS-e Barueri
      description: Re-busca la NFS-e en la municipalidad de Barueri y la compara con el registro local, devolviendo la lista de diferencias y el XML actualizado para reaplicación vía `POST /nfes/import-barueri`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la NF-e.
          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-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 validación con diferencias y XML actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NfeValidateBarueriResponse"
        "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-nfes-id-validate-barueri
  /v1/proposals:
    get:
      tags:
        - Propuestas
      summary: Listar propuestas
      description: Devuelve una lista paginada de las propuestas comerciales 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
            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
        - schema:
            type: string
            enum:
              - draft
              - sent
              - viewed
              - accepted
              - rejected
              - expired
              - canceled
            description: "Filtra por estado: `draft`, `sent`, `viewed`, `accepted`, `rejected`, `expired` o `canceled`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `billing_account_id` vinculado.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `prospect_id`.
          required: false
          name: prospect_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `contact_id` vinculado.
          required: false
          name: contact_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `coupon_id` aplicado.
          required: false
          name: coupon_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `company_id` emisor.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por `template_id` usado para generar el PDF.
          required: false
          name: template_id
          in: query
        - schema:
            type: string
            description: "Filtra por código corto de la propuesta (ej.: `PROP-0001`)."
          required: false
          name: code
          in: query
        - schema:
            type: string
            description: Filtra por identificador externo.
          required: false
          name: external_id
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre.
          required: false
          name: search
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `expires_at` inicial (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: expires_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `expires_at` final (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: expires_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `accepted_at` inicial (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: accepted_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `accepted_at` final (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: accepted_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `sent_at` inicial (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: sent_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `sent_at` final (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: sent_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `viewed_at` inicial (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: viewed_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `viewed_at` final (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: viewed_before
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `rejected_at` inicial (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: rejected_after
          in: query
        - schema:
            type: string
            format: date
            description: Filtra por `rejected_at` final (ISO 8601, inclusivo).
            example: 2026-01-15
          required: false
          name: rejected_before
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Filtra por `setup_amount` mínimo (en BRL).
            example: 100
          required: false
          name: setup_amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Filtra por `setup_amount` máximo (en BRL).
            example: 100
          required: false
          name: setup_amount_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Filtra por `monthly_amount` mínimo (en BRL).
            example: 100
          required: false
          name: monthly_amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Filtra por `monthly_amount` máximo (en BRL).
            example: 100
          required: false
          name: monthly_amount_max
          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-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 propuestas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalListResponse"
        "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-proposals
    post:
      tags:
        - Propuestas
      summary: Crear propuesta
      description: Crea una propuesta comercial. Es obligatorio informar `billing_account_id`, `prospect_id` o `prospect_data` (creación inline del prospect).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalCreateRequest"
      responses:
        "201":
          description: Propuesta creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals
      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-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:
        - Propuestas
      summary: Crear o actualizar propuesta
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalUpsertResponse"
        "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-proposals
      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-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/proposals/stats:
    get:
      tags:
        - Propuestas
      summary: Obtener estadísticas de propuestas
      description: Devuelve conteos de propuestas por estado (`draft`, `sent`, `viewed`, `accepted`, `rejected`, `expired`, `canceled`) para la organización actual.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Estadísticas de propuestas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalStatsResponse"
        "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-proposals-stats
      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-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/proposals/bulk-cancel:
    post:
      tags:
        - Propuestas
      summary: Cancelar propuestas en lote
      description: Cancela varias propuestas a la vez (hasta 100). Devuelve conteos de éxito/fallo y errores por id.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalBulkRequest"
      responses:
        "200":
          description: Resultado de la cancelación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalBulkResponse"
        "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-proposals-bulk-cancel
      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-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/proposals/bulk-delete:
    post:
      tags:
        - Propuestas
      summary: Eliminar propuestas en lote
      description: Elimina varias propuestas a la vez (hasta 100). Devuelve conteos de éxito/fallo y errores por id.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalBulkRequest"
      responses:
        "200":
          description: Resultado de la eliminación en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalBulkResponse"
        "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-proposals-bulk-delete
      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-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/proposals/bulk-send:
    post:
      tags:
        - Propuestas
      summary: Enviar propuestas en lote
      description: Envía varias propuestas a la vez (hasta 100). Devuelve conteos de éxito/fallo y errores por id.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalBulkRequest"
      responses:
        "200":
          description: Resultado del envío en lote.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalBulkResponse"
        "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-proposals-bulk-send
      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-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/proposals/{id}:
    get:
      tags:
        - Propuestas
      summary: Obtener propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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 de la propuesta.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id
    patch:
      tags:
        - Propuestas
      summary: Actualizar propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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/ProposalUpdateRequest"
      responses:
        "200":
          description: Propuesta actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id
    delete:
      tags:
        - Propuestas
      summary: Eliminar propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Propuesta eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalDeletedResponse"
        "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-proposals-id
  /v1/proposals/{id}/accept:
    post:
      tags:
        - Propuestas
      summary: Aceptar propuesta
      description: Acepta la propuesta y crea (o confirma) la suscripción correspondiente en el ciclo informado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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/ProposalAcceptRequest"
      responses:
        "200":
          description: Propuesta aceptada — devuelve la propuesta, `subscription_id` e `invoice_id` cuando aplican.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalAcceptResponse"
        "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-proposals-id-accept
  /v1/proposals/{id}/cancel:
    post:
      tags:
        - Propuestas
      summary: Cancelar propuesta
      description: Cancela la propuesta (`status → canceled`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Propuesta cancelada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-cancel
  /v1/proposals/{id}/duplicate:
    post:
      tags:
        - Propuestas
      summary: Duplicar propuesta
      description: Crea una nueva propuesta a partir de la original (borrador), preservando ítems y configuración.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Propuesta duplicada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-duplicate
  /v1/proposals/{id}/send:
    post:
      tags:
        - Propuestas
      summary: Enviar propuesta por correo
      description: "Envía (o reenvía) la propuesta por correo al destinatario. Estados permitidos: `draft`, `sent` o `viewed`. Opcionalmente personaliza `subject` y `message` (HTML)."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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/ProposalSendRequest"
      responses:
        "200":
          description: Propuesta enviada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-send
  /v1/proposals/{id}/publish:
    post:
      tags:
        - Propuestas
      summary: Publicar propuesta
      description: Publica la propuesta (`draft → sent`) sin enviar el correo, dejándola disponible en el portal.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Propuesta publicada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-publish
  /v1/proposals/{id}/unpublish:
    post:
      tags:
        - Propuestas
      summary: Despublicar propuesta
      description: Vuelve la propuesta a borrador (`sent`/`viewed` → `draft`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Propuesta despublicada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-unpublish
  /v1/proposals/{id}/undo-accept:
    post:
      tags:
        - Propuestas
      summary: Deshacer aceptación de la propuesta
      description: "Deshace la aceptación: elimina la suscripción vinculada y vuelve el estado a `sent`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Aceptación deshecha.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalResponse"
        "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-proposals-id-undo-accept
  /v1/proposals/{id}/generate-pdf:
    post:
      tags:
        - Propuestas
      summary: Generar PDF de la propuesta
      description: Genera (o regenera) el PDF de la propuesta vía Google App Scripts. Requiere un `template` con `app_script_url` configurado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: PDF generado — devuelve la propuesta actualizada y las URLs del documento/PDF.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalGeneratePdfResponse"
        "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-proposals-id-generate-pdf
  /v1/proposals/{id}/json:
    get:
      tags:
        - Propuestas
      summary: Obtener snapshot JSON de la propuesta
      description: Devuelve el snapshot completo de los datos usados para renderizar el template del PDF (espeja lo que recibe AppScript).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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: Snapshot JSON de la propuesta.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalJsonResponse"
        "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-proposals-id-json
  /v1/proposals/{id}/pricing:
    get:
      tags:
        - Propuestas
      summary: Obtener cálculo de precio de la propuesta
      description: Devuelve el detalle de precios por ciclo de cobro (mensual, trimestral, semestral, anual), con setup y descuentos aplicados.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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 de precios.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalPricingResponse"
        "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-proposals-id-pricing
  /v1/proposals/{id}/items:
    get:
      tags:
        - Propuestas
      summary: Listar ítems de la propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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 de ítems.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalItemsListResponse"
        "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-proposals-id-items
    post:
      tags:
        - Propuestas
      summary: Agregar ítem a la propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          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-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/ProposalItemCreateRequest"
      responses:
        "201":
          description: Ítem creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalItemResponse"
        "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-proposals-id-items
  /v1/proposals/{id}/items/{item_id}:
    get:
      tags:
        - Propuestas
      summary: Obtener ítem de la propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de la propuesta.
          required: true
          name: item_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-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 ítem.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalItemResponse"
        "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-proposals-id-items-item-id
    patch:
      tags:
        - Propuestas
      summary: Actualizar ítem de la propuesta
      description: Actualiza un ítem. Solo permitido en propuestas en borrador (`status = draft`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de la propuesta.
          required: true
          name: item_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-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/ProposalItemUpdateRequest"
      responses:
        "200":
          description: Ítem actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalItemResponse"
        "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-proposals-id-items-item-id
    delete:
      tags:
        - Propuestas
      summary: Eliminar ítem de la propuesta
      description: Elimina un ítem. Solo permitido en propuestas en borrador (`status = draft`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la propuesta.
          required: true
          name: id
          in: path
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de la propuesta.
          required: true
          name: item_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-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: Ítem eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalDeletedResponse"
        "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-proposals-id-items-item-id
  /v1/proposal_templates:
    get:
      tags:
        - Plantillas de Propuesta
      summary: Listar plantillas de propuesta
      description: Devuelve una lista paginada de las plantillas de propuesta 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 descripción.
          required: false
          name: search
          in: query
        - schema:
            type: boolean
            description: Filtra por plantillas activas (`true`) o desactivadas (`false`).
          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-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 plantillas de propuesta.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateListResponse"
        "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-proposal-templates
    post:
      tags:
        - Plantillas de Propuesta
      summary: Crear plantilla de propuesta
      description: Crea una plantilla de propuesta vinculada a un Google Doc o Google Slides. El `google_doc_id` debe ser único por organización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalTemplateCreateRequest"
      responses:
        "201":
          description: Plantilla de propuesta creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-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-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:
        - Plantillas de Propuesta
      summary: Crear o actualizar plantilla de propuesta
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ProposalTemplateUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateUpsertResponse"
        "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-proposal-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-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/proposal_templates/{id}:
    get:
      tags:
        - Plantillas de Propuesta
      summary: Obtener plantilla de propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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 de la plantilla de propuesta.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-templates-id
    patch:
      tags:
        - Plantillas de Propuesta
      summary: Actualizar plantilla de propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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/ProposalTemplateUpdateRequest"
      responses:
        "200":
          description: Plantilla de propuesta actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-templates-id
    delete:
      tags:
        - Plantillas de Propuesta
      summary: Eliminar plantilla de propuesta
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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 de propuesta 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-proposal-templates-id
  /v1/proposal_templates/{id}/activate:
    post:
      tags:
        - Plantillas de Propuesta
      summary: Activar plantilla de propuesta
      description: Activa una plantilla de propuesta previamente desactivada, dejándola disponible para usar en nuevas propuestas.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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 de propuesta activada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-templates-id-activate
  /v1/proposal_templates/{id}/deactivate:
    post:
      tags:
        - Plantillas de Propuesta
      summary: Desactivar plantilla de propuesta
      description: Desactiva una plantilla de propuesta. Las plantillas desactivadas no pueden usarse en nuevas propuestas, pero las propuestas ya creadas permanecen sin cambios.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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 de propuesta desactivada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-templates-id-deactivate
  /v1/proposal_templates/{id}/duplicate:
    post:
      tags:
        - Plantillas de Propuesta
      summary: Duplicar plantilla de propuesta
      description: Crea una copia de la plantilla indicada, manteniendo la configuración y los metadatos. La nueva plantilla recibe un nombre derivado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la plantilla de propuesta.
          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-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: Plantilla de propuesta duplicada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ProposalTemplateResponse"
        "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-proposal-templates-id-duplicate
  /v1/plan_changes:
    get:
      tags:
        - Cambios de Plan
      summary: Listar cambios de plan
      description: Devuelve el historial paginado de cambios de plan (upgrades, downgrades y laterales) 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
            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
        - schema:
            type: string
            format: uuid
            description: Filtra por los cambios de una suscripción.
          required: false
          name: subscription_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los cambios de una cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por el plan de origen (UUID).
          required: false
          name: from_plan_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por el plan de destino (UUID).
          required: false
          name: to_plan_id
          in: query
        - schema:
            type: string
            enum:
              - upgrade
              - downgrade
              - lateral
            description: "Filtra por tipo: `upgrade`, `downgrade` o `lateral`."
          required: false
          name: change_type
          in: query
        - schema:
            type: string
            enum:
              - pending
              - scheduled
              - completed
              - canceled
              - failed
            description: "Filtra por estado: `pending`, `scheduled`, `completed`, `canceled` o `failed`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            enum:
              - immediate
              - end_of_period
            description: "Filtra por timing: `immediate` o `end_of_period`."
          required: false
          name: timing
          in: query
        - schema:
            type: string
            description: "Filtra por el método de prorrateo (ej.: `full_proration`, `no_proration`, `partial_proration`)."
          required: false
          name: proration_method
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Diferencia de precio mínima en R$. Ej.: `10.50`."
            example: 100
          required: false
          name: price_difference_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Diferencia de precio máxima en R$. Ej.: `500.00`."
            example: 100
          required: false
          name: price_difference_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Cargo de prorrateo mínimo en R$.
            example: 100
          required: false
          name: proration_charge_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Cargo de prorrateo máximo en R$.
            example: 100
          required: false
          name: proration_charge_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Crédito de prorrateo mínimo en R$.
            example: 100
          required: false
          name: proration_credit_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Crédito de prorrateo máximo en R$.
            example: 100
          required: false
          name: proration_credit_max
          in: query
        - schema:
            type: string
            format: date
            description: "Fecha de vigencia desde (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: effective_date_from
          in: query
        - schema:
            type: string
            format: date
            description: "Fecha de vigencia hasta (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: effective_date_to
          in: query
        - schema:
            type: string
            format: date
            description: "Fecha programada desde (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: scheduled_date_from
          in: query
        - schema:
            type: string
            format: date
            description: "Fecha programada hasta (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: scheduled_date_to
          in: query
        - schema:
            type: string
            format: date
            description: "Completada desde (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: completed_after
          in: query
        - schema:
            type: string
            format: date
            description: "Completada hasta (inclusive). Formato: `YYYY-MM-DD`."
            example: 2026-01-15
          required: false
          name: completed_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 cambios de plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeListResponse"
        "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-plan-changes
    post:
      tags:
        - Cambios de Plan
      summary: Ejecutar cambio de plan
      description: Ejecuta un cambio de plan para una suscripción existente. `timing` controla si el cambio se aplica de inmediato (con prorrateo) o al final del período actual. En caso de éxito, devuelve los UUIDs del `plan_change`, la factura de prorrateo (si existe) y el crédito generado (si existe).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanChangeExecuteRequest"
      responses:
        "201":
          description: Cambio de plan ejecutado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeExecuteResponse"
        "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-plan-changes
      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-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/plan_changes/stats:
    get:
      tags:
        - Cambios de Plan
      summary: Estadísticas de cambios de plan
      description: Devuelve agregados de cambios de plan (totales por tipo, por estado, créditos y cargos de prorrateo) para una ventana en días.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: integer
            minimum: 1
            description: "Ventana en días para los agregados (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-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: Estadísticas agregadas de cambios de plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeStatsResponse"
        "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-plan-changes-stats
  /v1/plan_changes/config:
    get:
      tags:
        - Cambios de Plan
      summary: Obtener configuración de cambio de plan
      description: Devuelve la configuración por defecto de la organización para upgrades y downgrades — comportamiento de prorrateo, timing y generación de crédito/refund.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Configuración actual.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeConfigResponse"
        "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-plan-changes-config
      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-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:
        - Cambios de Plan
      summary: Actualizar configuración de cambio de plan
      description: Actualiza parcialmente (PATCH) la configuración de cambio de plan de la organización. Todos los campos son opcionales.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanChangeConfigUpdateRequest"
      responses:
        "200":
          description: Configuración actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeConfigResponse"
        "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-plan-changes-config
      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-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/plan_changes/rules:
    get:
      tags:
        - Cambios de Plan
      summary: Listar reglas de cambio de plan
      description: Lista las reglas personalizadas que sobrescriben el comportamiento por defecto para transiciones específicas entre planes.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Lista de reglas de cambio de plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeRuleListResponse"
        "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-plan-changes-rules
      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-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:
        - Cambios de Plan
      summary: Crear regla de cambio de plan
      description: Crea una nueva regla para una transición entre planes. Permite bloquear/permitir la transición, definir timing, prorrateo, descuentos y días bonus.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PlanChangeRuleCreateRequest"
      responses:
        "201":
          description: Regla creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeRuleResponse"
        "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-plan-changes-rules
      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-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/plan_changes/rules/{id}:
    get:
      tags:
        - Cambios de Plan
      summary: Obtener regla de cambio de plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla de cambio de plan.
          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-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 de la regla.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeRuleResponse"
        "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-plan-changes-rules-id
    patch:
      tags:
        - Cambios de Plan
      summary: Actualizar regla de cambio de plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla de cambio de plan.
          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-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/PlanChangeRuleUpdateRequest"
      responses:
        "200":
          description: Regla actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeRuleResponse"
        "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-plan-changes-rules-id
    delete:
      tags:
        - Cambios de Plan
      summary: Eliminar regla de cambio de plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla de cambio de plan.
          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-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: Regla eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeRuleDeletedResponse"
        "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-plan-changes-rules-id
  /v1/plan_changes/{id}:
    get:
      tags:
        - Cambios de Plan
      summary: Obtener cambio de plan
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cambio de plan.
          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-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 cambio de plan.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlanChangeResponse"
        "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-plan-changes-id
  /v1/subscription_changes/config:
    get:
      tags:
        - Cambios de Suscripción
      summary: Obtener configuración de cambios de suscripción
      description: Devuelve la configuración de la organización para cambios en ítems de suscripción — operaciones permitidas (agregar/eliminar/cambiar cantidad/cambiar precio), método de prorrateo por operación, momento de aplicación (`immediate` o `end_of_period`), reembolso/crédito al eliminar y self-service en el portal. Si aún no existe, se crea con los valores por defecto en la primera lectura.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Configuración de la organización.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionChangeConfigResponse"
        "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-subscription-changes-config
      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-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:
        - Cambios de Suscripción
      summary: Actualizar configuración de cambios de suscripción
      description: Actualiza parcialmente la configuración. Solo se modifican los campos enviados. `refund_on_remove` requiere que `credit_on_remove` también esté habilitado — el reembolso es una variante del crédito.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SubscriptionChangeConfigUpdateRequest"
      responses:
        "200":
          description: Configuración actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionChangeConfigResponse"
        "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-subscription-changes-config
      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-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/subscription_item_changes:
    get:
      tags:
        - Cambios de Suscripción
      summary: Listar cambios de ítems de suscripción
      description: Devuelve una lista paginada de los cambios aplicados (o agendados) sobre ítems de suscripciones de la organización — agregados, eliminaciones, cambios de cantidad y cambios de precio. Cada registro incluye el snapshot de las operaciones, los montos de prorrateo en BRL (float, hasta 4 decimales) y los punteros a la factura/credit generados.
      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
            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
        - schema:
            type: string
            format: uuid
            description: Filtra por los cambios de una suscripción específica.
          required: false
          name: subscription_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por los cambios de una cuenta de cobro específica.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            enum:
              - pending
              - scheduled
              - completed
              - canceled
              - failed
            description: "Filtra por estado: `pending`, `scheduled`, `completed`, `canceled` o `failed`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            enum:
              - immediate
              - end_of_period
            description: "Filtra por el momento de aplicación del cambio: `immediate` o `end_of_period`."
          required: false
          name: timing
          in: query
        - schema:
            type: string
            enum:
              - dashboard
              - portal
              - api
            description: "Filtra por el origen del cambio: `dashboard`, `portal` o `api`."
          required: false
          name: initiated_by_role
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo del cargo de prorrateo, en reales (R$). Almacenado internamente en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: proration_charge_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo del cargo de prorrateo, en reales (R$). Almacenado internamente en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: proration_charge_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo del crédito de prorrateo, en reales (R$). Almacenado internamente en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: proration_credit_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo del crédito de prorrateo, en reales (R$). Almacenado internamente en BRL (float, hasta 4 decimales).
            example: 100
          required: false
          name: proration_credit_max
          in: query
        - schema:
            type: string
            format: date
            description: Fecha efectiva mínima del cambio (inclusive), en formato `YYYY-MM-DD`.
            example: 2026-01-15
          required: false
          name: effective_date_from
          in: query
        - schema:
            type: string
            format: date
            description: Fecha efectiva máxima del cambio (inclusive), en formato `YYYY-MM-DD`.
            example: 2026-01-15
          required: false
          name: effective_date_to
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 cambios de ítems.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionItemChangeListResponse"
        "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-subscription-item-changes
  /v1/subscription_item_changes/{id}:
    get:
      tags:
        - Cambios de Suscripción
      summary: Obtener cambio de ítem de suscripción
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cambio de ítem.
          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-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 cambio de ítem.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionItemChangeResponse"
        "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-subscription-item-changes-id
    delete:
      tags:
        - Cambios de Suscripción
      summary: Cancela un cambio agendado
      description: Cancela un cambio de ítems aún agendado (`timing=end_of_period`). Los cambios ya aplicados no pueden cancelarse. Devuelve el registro con su nuevo estado.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del cambio de ítem.
          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-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: Cambio cancelado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionItemChangeResponse"
        "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-subscription-item-changes-id
  /v1/usage:
    get:
      tags:
        - Uso (Medido)
      summary: Listar registros de uso
      description: Devuelve los registros de uso (metered) de un ítem de suscripción. Identifica el ítem por `subscription_item_id` **o** por la combinación `product_slug` + `customer_id`. Admite filtros por rango de fechas y ventana `limit`/`offset`.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de suscripción. Alternativa a `product_slug` + `customer_id`.
          required: false
          name: subscription_item_id
          in: query
        - schema:
            type: string
            description: Slug del producto. Combina con `customer_id`.
          required: false
          name: product_slug
          in: query
        - schema:
            type: string
            description: Identificador externo del cliente. Combina con `product_slug`.
          required: false
          name: customer_id
          in: query
        - schema:
            type: string
            description: Fecha/hora inicial del filtro — formato ISO 8601.
          required: false
          name: start_date
          in: query
        - schema:
            type: string
            description: Fecha/hora final del filtro — formato ISO 8601.
          required: false
          name: end_date
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 1000
            description: "Ítems por página. Por defecto: `100`. Máximo: `1000`."
          required: false
          name: limit
          in: query
        - schema:
            type:
              - integer
              - "null"
            minimum: 0
            description: "Desplazamiento (offset) para paginación. Por defecto: `0`."
          required: false
          name: offset
          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-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 de registros de uso con agregación `total_quantity` en `meta`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageListResponse"
        "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-usage
    post:
      tags:
        - Uso (Medido)
      summary: Reportar uso (metered)
      description: "Reporta uso para facturación metered. Acepta un registro único **o** un lote `{ records: [...] }` con hasta **100** ítems. Cada registro debe identificar el ítem de suscripción por `subscription_item_id` **o** por `product_slug` + `customer_id` (recomendado para integraciones externas). El precio/producto debe estar configurado con `usage_type=metered` y la suscripción debe estar `active` o `trialing`. Usa `idempotency_key` para evitar duplicados — cuando la clave ya fue vista, la respuesta marca `duplicate: true`. Los lotes con fallas parciales devuelven **207 Multi-Status**."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UsageRecordCreateRequest"
      responses:
        "200":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageRecordCreateResponse"
        "207":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageRecordCreateResponse"
        "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-usage
      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-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/summary:
    get:
      tags:
        - Uso (Medido)
      summary: Resumen de uso del período
      description: Devuelve la agregación de uso de un ítem de suscripción en el período de cobro vigente (o en un período arbitrario vía `period_start`/`period_end`). Considera registros `set` (que reemplazan) y la suma de los `increment` posteriores. Cuando el precio es por tiers o unitario, calcula un costo estimado en `estimated_cost` (float, hasta 4 decimales).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de suscripción. Alternativa a `product_slug` + `customer_id`.
          required: false
          name: subscription_item_id
          in: query
        - schema:
            type: string
            description: Slug del producto. Combina con `customer_id`.
          required: false
          name: product_slug
          in: query
        - schema:
            type: string
            description: Identificador externo del cliente. Combina con `product_slug`.
          required: false
          name: customer_id
          in: query
        - schema:
            type: string
            description: "Inicio del período (ISO 8601). Por defecto: `current_period_start` de la suscripción."
          required: false
          name: period_start
          in: query
        - schema:
            type: string
            description: "Fin del período (ISO 8601). Por defecto: `current_period_end` de la suscripción."
          required: false
          name: period_end
          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-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 uso, período y costo estimado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageSummaryResponse"
        "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-usage-summary
  /v1/usage/snapshots/daily:
    get:
      tags:
        - Uso (Medido)
      summary: Listar snapshots diarios de uso
      description: "Lista los snapshots diarios de uso de la organización. Filtros opcionales: `billing_account_id`, `product_id` y ventana `start_date`/`end_date`. Admite paginación por `limit`/`offset`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: Filtra snapshots por UUID de la cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra snapshots por UUID del producto.
          required: false
          name: product_id
          in: query
        - schema:
            type: string
            description: Fecha/hora inicial del filtro — formato ISO 8601.
          required: false
          name: start_date
          in: query
        - schema:
            type: string
            description: Fecha/hora final del filtro — formato ISO 8601.
          required: false
          name: end_date
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 1000
            description: "Ítems por página. Por defecto: `100`. Máximo: `1000`."
          required: false
          name: limit
          in: query
        - schema:
            type:
              - integer
              - "null"
            minimum: 0
            description: "Desplazamiento (offset) para paginación. Por defecto: `0`."
          required: false
          name: offset
          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-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 de snapshots diarios con `meta` que incluye `total`, `limit`, `offset`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageDailySnapshotListResponse"
        "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-snapshots-daily
    post:
      tags:
        - Uso (Medido)
      summary: Crear snapshots diarios de uso
      description: "Crea snapshots diarios de uso, registro único **o** lote `{ records: [...] }` con hasta **100** ítems. La clave natural (organización, cuenta de cobro, producto, fecha) es única: si ya existe, el snapshot es sobrescrito (`overwritten: true`). Resuelve la cuenta por `billing_account_id` **o** `billing_account_public_id` y el producto por `product_slug` **o** `product_id` dentro del `product_group_slug` informado. Los lotes con fallas parciales devuelven **207 Multi-Status**."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UsageDailySnapshotCreateRequest"
      responses:
        "200":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageDailySnapshotCreateResponse"
        "207":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageDailySnapshotCreateResponse"
        "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-usage-snapshots-daily
      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-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/snapshots/monthly:
    get:
      tags:
        - Uso (Medido)
      summary: Listar snapshots mensuales de uso
      description: "Lista los snapshots mensuales de uso de la organización. Filtros opcionales: `billing_account_id`, `product_id` y ventana `start_month`/`end_month`. Admite paginación por `limit`/`offset`."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: Filtra snapshots por UUID de la cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra snapshots por UUID del producto.
          required: false
          name: product_id
          in: query
        - schema:
            type: string
            description: Mes inicial del filtro en formato `YYYY-MM-DD` (primer día del mes).
          required: false
          name: start_month
          in: query
        - schema:
            type: string
            description: Mes final del filtro en formato `YYYY-MM-DD` (primer día del mes).
          required: false
          name: end_month
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 1000
            description: "Ítems por página. Por defecto: `100`. Máximo: `1000`."
          required: false
          name: limit
          in: query
        - schema:
            type:
              - integer
              - "null"
            minimum: 0
            description: "Desplazamiento (offset) para paginación. Por defecto: `0`."
          required: false
          name: offset
          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-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 de snapshots mensuales con `meta` que incluye `total`, `limit`, `offset`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageMonthlySnapshotListResponse"
        "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-snapshots-monthly
    post:
      tags:
        - Uso (Medido)
      summary: Crear snapshots mensuales de uso
      description: "Crea snapshots mensuales de uso, registro único **o** lote `{ records: [...] }` con hasta **100** ítems. La clave natural (organización, cuenta de cobro, producto, mes) es única: si ya existe, el snapshot es sobrescrito (`overwritten: true`). Resuelve la cuenta por `billing_account_id` **o** `billing_account_public_id` y el producto por `product_slug` **o** `product_id` dentro de `product_group_slug`. Los lotes con fallas parciales devuelven **207 Multi-Status**."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UsageMonthlySnapshotCreateRequest"
      responses:
        "200":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageMonthlySnapshotCreateResponse"
        "207":
          description: Resultado del procesamiento (registro único o lote).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/UsageMonthlySnapshotCreateResponse"
        "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-usage-snapshots-monthly
      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-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/credits/daily:
    post:
      tags:
        - Uso (Medido)
      summary: Publicar consumo diario de créditos
      description: "Publica el consumo de créditos prepagos (producto de tipo `credits`) por cuenta de cobro × producto × día, registro único **o** en lote `{ records: [...] }` con hasta **100** ítems. La clave (cuenta, producto, `usage_date`) es única: publicar el mismo día de nuevo **sobrescribe** el registro (`overwritten: true`), nunca suma. Los lotes con fallos parciales devuelven **207 Multi-Status**."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditUsageDailyRequest"
      responses:
        "200":
          description: Registros procesados (`207` cuando parte del lote falló).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditUsageDailyResponse"
        "207":
          description: Registros procesados (`207` cuando parte del lote falló).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditUsageDailyResponse"
        "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-usage-credits-daily
      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-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/credits:
    get:
      tags:
        - Uso (Medido)
      summary: Consultar consumo y saldo de créditos
      description: Devuelve el consumo de créditos prepagos en el período (totales y serie diaria) y el saldo actual. Sin `billing_account_id`, suma todas las cuentas de la organización. Sin fechas, usa el mes actual (huso de São Paulo).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: Filtra por cuenta de cobro.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            format: uuid
            description: "Producto de créditos. Por defecto: el primer producto activo."
          required: false
          name: product_id
          in: query
        - schema:
            type: string
            description: Inicio del período (`YYYY-MM-DD`).
          required: false
          name: start_date
          in: query
        - schema:
            type: string
            description: Fin del período, inclusive (`YYYY-MM-DD`).
          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-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: Consumo del período y saldo.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreditUsageReportResponse"
        "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-credits
  /v1/credit_purchases:
    post:
      tags:
        - Uso (Medido)
      summary: Comprar créditos
      description: "Genera y finaliza una factura independiente (`billing_reason = credit_purchase`) con la cantidad de créditos de un producto de tipo `credits`, sin depender de una suscripción. El saldo vale cuando la factura se paga: el webhook `invoice.paid` trae `line_items[].product_type` y `quantity`."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreditPurchaseCreateRequest"
      responses:
        "201":
          description: Factura de la compra, con sus ítems.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvoiceResponse"
        "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-credit-purchases
      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-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/tax_rules:
    get:
      tags:
        - Reglas Tributarias
      summary: Listar reglas tributarias
      description: Devuelve una lista paginada de las reglas tributarias de la organización actual. Usa los filtros `scope`, `company_id`, `service_item_id`, `billing_account_id` e `is_active` para acotar el resultado.
      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:
              - global
              - organization
              - company
              - service
              - customer
              - municipality
            description: "Filtra por alcance: `global`, `organization`, `company`, `service`, `customer` o `municipality`."
          required: false
          name: scope
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las reglas de una empresa específica.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las reglas de un ítem de servicio específico.
          required: false
          name: service_item_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las reglas de una cuenta de cobro específica.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Cuando es `true`, devuelve solo reglas activas; cuando es `false`, solo inactivas.
          required: false
          name: is_active
          in: query
        - schema:
            type: string
            description: Búsqueda textual en `name` y `description`.
          required: false
          name: search
          in: query
        - schema:
            type: string
            description: "Filtra por tipo tributario del cliente: `pessoa_fisica`, `pessoa_juridica`, `mei`, `simples_optante` o `entidade_publica`."
          required: false
          name: customer_tax_type
          in: query
        - schema:
            type: string
            description: "Filtra por tipo de operación: `interno` (mismo municipio) o `externo` (municipio diferente)."
          required: false
          name: operation_type
          in: query
        - schema:
            type: string
            description: Filtra por el código IBGE del municipio (7 dígitos).
          required: false
          name: municipality
          in: query
        - schema:
            type:
              - integer
              - "null"
            description: Prioridad mínima (inclusiva) para filtrar reglas.
          required: false
          name: priority_from
          in: query
        - schema:
            type:
              - integer
              - "null"
            description: Prioridad máxima (inclusiva) para filtrar reglas.
          required: false
          name: priority_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve reglas cuya fecha de inicio de vigencia sea igual o posterior a este valor (ISO 8601).
            example: 2026-01-15
          required: false
          name: effective_from_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve reglas cuya fecha de inicio de vigencia sea igual o anterior a este valor (ISO 8601).
            example: 2026-01-15
          required: false
          name: effective_from_to
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve reglas cuya fecha de fin de vigencia sea igual o posterior a este valor (ISO 8601).
            example: 2026-01-15
          required: false
          name: effective_to_from
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve reglas cuya fecha de fin de vigencia sea igual o anterior a este valor (ISO 8601).
            example: 2026-01-15
          required: false
          name: effective_to_to
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 reglas tributarias.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleListResponse"
        "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-tax-rules
    post:
      tags:
        - Reglas Tributarias
      summary: Crear regla tributaria
      description: Crea una nueva regla tributaria con sus ítems (alícuotas por tributo). El `scope` define el nivel de aplicación y la `priority` define la precedencia — las reglas de mayor prioridad sobrescriben a las menores. Es obligatorio informar al menos un ítem en `items`.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TaxRuleCreateRequest"
      responses:
        "201":
          description: Regla tributaria creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleResponse"
        "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-tax-rules
      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-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:
        - Reglas Tributarias
      summary: Crear o actualizar regla fiscal
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TaxRuleUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleUpsertResponse"
        "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-tax-rules
      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-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/tax_rules/{id}:
    get:
      tags:
        - Reglas Tributarias
      summary: Obtener regla tributaria
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla tributaria.
          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-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 de la regla tributaria.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleResponse"
        "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-tax-rules-id
    patch:
      tags:
        - Reglas Tributarias
      summary: Actualizar regla tributaria
      description: Actualiza los campos editables de la regla. Cuando se informa `items`, **reemplaza** por completo la lista de ítems existente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla tributaria.
          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-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/TaxRuleUpdateRequest"
      responses:
        "200":
          description: Regla tributaria actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleResponse"
        "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-tax-rules-id
    delete:
      tags:
        - Reglas Tributarias
      summary: Eliminar regla tributaria
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la regla tributaria.
          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-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: Regla tributaria eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxRuleDeletedResponse"
        "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-tax-rules-id
  /v1/late_fee_policies:
    get:
      tags:
        - Intereses y Multas
      summary: Listar políticas de intereses y multas
      description: 'Devuelve las políticas de intereses y multas de la organización. La política aplicada a una factura se resuelve en cascada: factura → suscripción → cuenta de cobro → política por defecto de la organización. Un nivel nulo significa heredar, nunca "sin cargo" — no cobrar nada es una política explícita con ambos modos en `none`.'
      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:
              - "true"
              - "false"
            description: Incluye políticas eliminadas lógicamente.
          required: false
          name: include_deleted
          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-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 políticas de intereses y multas.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyListResponse"
        "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-late-fee-policies
    post:
      tags:
        - Intereses y Multas
      summary: Crear política de intereses y multas
      description: Crea una política. Multa e intereses por encima de los topes legales (2% de multa y 1% mensual de intereses, CDC art. 52) se rechazan salvo que `enforce_legal_caps` sea `false` — lo cual se audita por separado, al ser una decisión de riesgo jurídico.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LateFeePolicyCreateRequest"
      responses:
        "201":
          description: Política creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyResponse"
        "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-late-fee-policies
      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-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/late_fee_policies/simulate:
    post:
      tags:
        - Intereses y Multas
      summary: Simular intereses y multas
      description: Calcula cuánto debe un saldo en multa e intereses en una fecha, sin crear nada. Informe `policy_id` o una `policy` inline. Sirve para conciliar el cálculo antes de que una factura venza de verdad.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/LateChargesSimulateRequest"
      responses:
        "200":
          description: Cargos devengados en la fecha indicada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateChargesSimulateResponse"
        "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-late-fee-policies-simulate
      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-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/late_fee_policies/{id}:
    get:
      tags:
        - Intereses y Multas
      summary: Consultar política de intereses y multas
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la política de intereses y multas.
          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-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: Política encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyResponse"
        "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-late-fee-policies-id
    patch:
      tags:
        - Intereses y Multas
      summary: Actualizar política de intereses y multas
      description: "Actualiza la política. Las facturas ya finalizadas no se ven afectadas: cada factura congela la política vigente al finalizar, de modo que una renegociación no cambie retroactivamente lo ya emitido."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la política de intereses y multas.
          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-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/LateFeePolicyUpdateRequest"
      responses:
        "200":
          description: Política actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyResponse"
        "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-late-fee-policies-id
    delete:
      tags:
        - Intereses y Multas
      summary: Eliminar política de intereses y multas
      description: Eliminación lógica. Las facturas ya emitidas siguen valiendo por el snapshot que llevan. La política por defecto no puede eliminarse — defina otra como predeterminada antes.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la política de intereses y multas.
          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-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: Política eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyDeletedResponse"
        "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-late-fee-policies-id
  /v1/late_fee_policies/{id}/default:
    post:
      tags:
        - Intereses y Multas
      summary: Definir como política por defecto
      description: Convierte esta en la política por defecto de la organización — lo que hereda una factura cuando ni ella, ni su suscripción, ni su cuenta de cobro indican una. Exactamente una política lleva la marca.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID de la política de intereses y multas.
          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-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: Política definida como predeterminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LateFeePolicyResponse"
        "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-late-fee-policies-id-default
  /v1/holidays:
    get:
      tags:
        - Feriados
      summary: Listar feriados
      description: Devuelve los feriados de la organización — los días que el conteo en días hábiles salta. Una política de intereses y multas con `day_count = business` lee exactamente esta tabla.
      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: integer
            minimum: 1900
            maximum: 2199
            description: Filtra por año civil.
          required: false
          name: year
          in: query
        - schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
            description: Fecha inicial, inclusiva, en formato `YYYY-MM-DD`.
          required: false
          name: date_from
          in: query
        - schema:
            type: string
            pattern: ^\d{4}-\d{2}-\d{2}$
            description: Fecha final, inclusiva, en formato `YYYY-MM-DD`.
          required: false
          name: date_to
          in: query
        - schema:
            type: string
            enum:
              - national
              - state
              - municipal
              - optional
              - custom
            description: Filtra por el alcance del feriado.
          required: false
          name: type
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: Incluye feriados eliminados lógicamente.
          required: false
          name: include_deleted
          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-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 feriados.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidayListResponse"
        "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-holidays
    post:
      tags:
        - Feriados
      summary: Crear feriado
      description: Crea un feriado. Úselo para feriados estatales, municipales y puntos facultativos — los nacionales llegan por la importación automática.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/HolidayCreateRequest"
      responses:
        "201":
          description: Feriado creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidayResponse"
        "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-holidays
      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-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/holidays/sync:
    post:
      tags:
        - Feriados
      summary: Importar feriados nacionales
      description: "Importa los feriados nacionales brasileños desde BrasilAPI para los años indicados (por omisión, el año corriente y los dos siguientes). Idempotente: importa solo lo que falta y nunca resucita un feriado eliminado a propósito."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/HolidaySyncRequest"
      responses:
        "200":
          description: Resultado de la importación.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidaySyncResponse"
        "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-holidays-sync
      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-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/holidays/{id}:
    get:
      tags:
        - Feriados
      summary: Consultar feriado
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del feriado.
          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-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: Feriado encontrado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidayResponse"
        "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-holidays-id
    patch:
      tags:
        - Feriados
      summary: Actualizar feriado
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del feriado.
          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-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/HolidayUpdateRequest"
      responses:
        "200":
          description: Feriado actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidayResponse"
        "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-holidays-id
    delete:
      tags:
        - Feriados
      summary: Eliminar feriado
      description: "Eliminación lógica. La fila permanece, y eso es lo que hace que la importación respete la remoción: un feriado quitado a propósito no vuelve en la próxima sincronización."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: ID del feriado.
          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-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: Feriado eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/HolidayDeletedResponse"
        "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-holidays-id
  /v1/banks:
    get:
      tags:
        - Bancos
      summary: Listar bancos
      description: Bancos brasileños con código COMPE (BACEN), usados en el registro de cuentas bancarias. La lista es la misma para todas las organizaciones y se actualiza semanalmente desde BrasilAPI.
      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 por parte del nombre o del código.
          required: false
          name: search
          in: query
        - schema:
            type: string
            description: "Código COMPE exacto (ej.: `341`)."
          required: false
          name: code
          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-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 bancos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankListResponse"
        "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-banks
  /v1/bank_accounts:
    get:
      tags:
        - Cuentas bancarias
      summary: Listar cuentas bancarias
      description: Cuentas bancarias de la organización a las que los clientes transfieren en un cobro `bank_transfer` (`POST /invoices/{id}/pay`).
      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:
              - "true"
              - "false"
            description: Filtra por cuentas activas (`true`) o inactivas (`false`).
          required: false
          name: active
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por banco (UUID de `/banks`).
          required: false
          name: bank_id
          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-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 cuentas bancarias.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankAccountListResponse"
        "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-bank-accounts
    post:
      tags:
        - Cuentas bancarias
      summary: Registrar cuenta bancaria
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BankAccountCreateRequest"
      responses:
        "201":
          description: Cuenta bancaria creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankAccountResponse"
        "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-bank-accounts
      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-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/bank_accounts/{id}:
    get:
      tags:
        - Cuentas bancarias
      summary: Consultar cuenta bancaria
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la cuenta bancaria.
          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-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: Cuenta bancaria encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankAccountResponse"
        "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-bank-accounts-id
    patch:
      tags:
        - Cuentas bancarias
      summary: Actualizar cuenta bancaria
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la cuenta bancaria.
          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-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/BankAccountUpdateRequest"
      responses:
        "200":
          description: Cuenta bancaria actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/BankAccountResponse"
        "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-bank-accounts-id
    delete:
      tags:
        - Cuentas bancarias
      summary: Eliminar cuenta bancaria
      description: Eliminación lógica. Los cobros ya enviados siguen mostrando los datos que recibió el cliente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la cuenta bancaria.
          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-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: Cuenta bancaria eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransferDestinationDeletedResponse"
        "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-bank-accounts-id
  /v1/pix_keys:
    get:
      tags:
        - Claves Pix
      summary: Listar claves Pix
      description: Claves Pix de la organización a las que los clientes transfieren en un cobro `bank_transfer` (`POST /invoices/{id}/pay`).
      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:
              - "true"
              - "false"
            description: Filtra por claves activas (`true`) o inactivas (`false`).
          required: false
          name: active
          in: query
        - schema:
            type: string
            enum:
              - cpf
              - cnpj
              - email
              - phone
              - random
            description: Filtra por tipo de clave.
          required: false
          name: key_type
          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-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 claves Pix.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PixKeyListResponse"
        "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-pix-keys
    post:
      tags:
        - Claves Pix
      summary: Registrar clave Pix
      description: El tipo se identifica por la propia clave (CPF, CNPJ, correo, teléfono con +55 o aleatoria); `key_type`, si se envía, debe coincidir. La clave se guarda sin máscara y es única en la organización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PixKeyCreateRequest"
      responses:
        "201":
          description: Clave Pix creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PixKeyResponse"
        "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-pix-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-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/pix_keys/{id}:
    get:
      tags:
        - Claves Pix
      summary: Consultar clave Pix
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la clave Pix.
          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-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: Clave Pix encontrada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PixKeyResponse"
        "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-pix-keys-id
    patch:
      tags:
        - Claves Pix
      summary: Actualizar clave Pix
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la clave Pix.
          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-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/PixKeyUpdateRequest"
      responses:
        "200":
          description: Clave Pix actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PixKeyResponse"
        "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-pix-keys-id
    delete:
      tags:
        - Claves Pix
      summary: Eliminar clave Pix
      description: Eliminación lógica. Los cobros ya enviados siguen mostrando los datos que recibió el cliente, y la clave puede registrarse de nuevo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID o `public_id` de la clave Pix.
          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-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: Clave Pix eliminada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransferDestinationDeletedResponse"
        "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-pix-keys-id
  /v1/tax_periods:
    get:
      tags:
        - Períodos Tributarios
      summary: Listar períodos tributarios
      description: Devuelve una lista paginada de los períodos tributarios (mensuales o trimestrales) de la organización. Permite filtrar por empresa, tipo de período, año y estado.
      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
            format: uuid
            description: Filtra por empresa emisora.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            enum:
              - monthly
              - quarterly
            description: "Filtra por tipo de período: `monthly` o `quarterly`."
          required: false
          name: period_type
          in: query
        - schema:
            type: string
            pattern: ^\d+$
            description: "Filtra por año de competencia (ej.: `2026`)."
          required: false
          name: year
          in: query
        - schema:
            type: string
            enum:
              - open
              - calculated
              - closed
            description: "Filtra por estado: `open`, `calculated` o `closed`."
          required: false
          name: status
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 12
            description: Filtra por mes de competencia (1 a 12).
          required: false
          name: month
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 4
            description: Filtra por trimestre de competencia (1 a 4).
          required: false
          name: quarter
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Ingreso bruto mínimo del período, en BRL (ej.: `1000.00`)."
            example: 100
          required: false
          name: gross_revenue_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Ingreso bruto máximo del período, en BRL (ej.: `50000.00`)."
            example: 100
          required: false
          name: gross_revenue_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "DAS estimado mínimo del período, en BRL (ej.: `100.00`)."
            example: 100
          required: false
          name: das_estimated_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "DAS estimado máximo del período, en BRL (ej.: `5000.00`)."
            example: 100
          required: false
          name: das_estimated_max
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve períodos cerrados desde esta fecha (formato `YYYY-MM-DD`).
            example: 2026-01-15
          required: false
          name: closed_after
          in: query
        - schema:
            type: string
            format: date
            description: Devuelve períodos cerrados hasta esta fecha (formato `YYYY-MM-DD`).
            example: 2026-01-15
          required: false
          name: closed_before
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 períodos tributarios.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxPeriodListResponse"
        "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-tax-periods
    post:
      tags:
        - Períodos Tributarios
      summary: Procesar período tributario mensual
      description: Crea (o recupera) el período tributario mensual indicado y calcula los impuestos debidos (ISS, PIS, COFINS, IRPJ, CSLL, CBS, IBS) con base en las NFes emitidas y las retenciones a compensar. Cuando se omite `company_id`, usa la empresa por defecto de la organización.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TaxPeriodCreateRequest"
      responses:
        "201":
          description: Período tributario procesado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxPeriodResponse"
        "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-tax-periods
      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-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/tax_periods/{id}:
    get:
      tags:
        - Períodos Tributarios
      summary: Obtener período tributario
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del período tributario.
          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-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 período tributario.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxPeriodResponse"
        "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-tax-periods-id
    patch:
      tags:
        - Períodos Tributarios
      summary: Ejecutar acción en el período tributario
      description: "Aplica una acción sobre el período: `recalculate` recalcula los impuestos (solo períodos mensuales), `close` cierra el período y `reopen` lo reabre."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del período tributario.
          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-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/TaxPeriodUpdateRequest"
      responses:
        "200":
          description: Período tributario actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxPeriodResponse"
        "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-tax-periods-id
    delete:
      tags:
        - Períodos Tributarios
      summary: Eliminar período tributario
      description: Elimina permanentemente el período tributario. Use con precaución — los períodos cerrados normalmente no deben eliminarse.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del período tributario.
          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-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: Período tributario eliminado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TaxPeriodDeletedResponse"
        "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-tax-periods-id
  /v1/withholdings:
    get:
      tags:
        - Retenciones
      summary: Listar retenciones
      description: Devuelve una lista paginada de las retenciones tributarias de la organización actual. Admite filtros por tipo de tributo, estado, retenedor, factura, NF-e y competencia.
      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
            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
        - schema:
            type: string
            enum:
              - iss
              - pis
              - cofins
              - csll
              - irpj
              - irrf
              - csrf
              - inss
              - cbs
              - ibs
            description: "Filtra por tipo de tributo: `iss`, `pis`, `cofins`, `csll`, `irpj`, `irrf`, `csrf`, `inss`, `cbs` o `ibs`."
          required: false
          name: tax_type
          in: query
        - schema:
            type: string
            enum:
              - retained
              - compensated
              - partially_compensated
            description: "Filtra por estado: `retained`, `compensated` o `partially_compensated`."
          required: false
          name: status
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las retenciones de un retenedor (cuenta de cobro) específico.
          required: false
          name: withholder_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las retenciones asociadas a una factura.
          required: false
          name: invoice_id
          in: query
        - schema:
            type: string
            format: uuid
            description: Filtra por las retenciones asociadas a una NF-e.
          required: false
          name: nfe_id
          in: query
        - schema:
            type: integer
            minimum: 2000
            maximum: 3000
            description: Filtra por el año de competencia (2000–3000).
          required: false
          name: competence_year
          in: query
        - schema:
            type: integer
            minimum: 1
            maximum: 12
            description: Filtra por el mes de competencia (1–12).
          required: false
          name: competence_month
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Monto mínimo retenido en BRL (ej.: `10.5` para R$ 10,50)."
            example: 100
          required: false
          name: amount_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: "Monto máximo retenido en BRL (ej.: `500.0` para R$ 500,00)."
            example: 100
          required: false
          name: amount_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Base de cálculo mínima en BRL.
            example: 100
          required: false
          name: base_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Base de cálculo máxima en BRL.
            example: 100
          required: false
          name: base_max
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto mínimo ya compensado en BRL.
            example: 100
          required: false
          name: compensated_min
          in: query
        - schema:
            type:
              - number
              - "null"
            minimum: 0
            description: Monto máximo ya compensado en BRL.
            example: 100
          required: false
          name: compensated_max
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 retenciones.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingListResponse"
        "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-withholdings
    post:
      tags:
        - Retenciones
      summary: Crea una retención
      description: Registra una retención en la fuente para el retenedor indicado. `base` y `amount` son valores en BRL (float, hasta 4 decimales).
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WithholdingCreateRequest"
      responses:
        "201":
          description: Retención creada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingResponse"
        "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-withholdings
      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-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:
        - Retenciones
      summary: Crea o actualiza una retención
      description: "Localiza la retención por `id`, `public_id` o `external_id`. Si no la encuentra, la crea con el cuerpo completo y devuelve `201`. **Si la encuentra, solo aplica `competence_month`, `competence_year`, `metadata`, `external_id` y `custom_metadata`**: `base`, `rate`, `amount` y `withholder_id` son inmutables tras el registro y se ignoran en el cuerpo de actualización."
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WithholdingUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingUpsertResponse"
        "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-withholdings
      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-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/withholdings/convert-to-credits:
    post:
      tags:
        - Retenciones
      summary: Convertir retenciones pendientes en créditos (en lote)
      description: Convierte todas las retenciones pendientes de la organización — opcionalmente acotadas por `tax_type` y/o competencia — en créditos. Devuelve la lista de créditos generados, la cantidad total convertida y el monto total en BRL.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/WithholdingBulkConvertRequest"
      responses:
        "200":
          description: Lote de retenciones convertido en créditos.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingBulkConvertResponse"
        "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-withholdings-convert-to-credits
      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-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/withholdings/{id}:
    get:
      tags:
        - Retenciones
      summary: Obtener retención
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la retenció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-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 de la retención.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingResponse"
        "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-withholdings-id
    patch:
      tags:
        - Retenciones
      summary: Actualiza una retención
      description: "Solo la competencia y los metadatos son editables: base, alícuota y monto quedan inmutables tras el registro."
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la retenció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-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/WithholdingUpdateRequest"
      responses:
        "200":
          description: Retención actualizada.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingResponse"
        "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-withholdings-id
    delete:
      tags:
        - Retenciones
      summary: Elimina una retención
      description: Rechaza la eliminación cuando la retención ya fue compensada, total o parcialmente.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la retenció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-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: Retención 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-withholdings-id
  /v1/withholdings/{id}/convert-to-credit:
    post:
      tags:
        - Retenciones
      summary: Convertir retención en crédito
      description: Convierte una retención (total o parcialmente) en un crédito en la cuenta de cobro derivada de la factura asociada — o, en su ausencia, del propio retenedor. Cuando se omite `amount`, convierte el saldo pendiente de la retención.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID de la retenció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-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/WithholdingConvertToCreditRequest"
      responses:
        "201":
          description: Crédito generado a partir de la retención.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/WithholdingConvertToCreditResponse"
        "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-withholdings-id-convert-to-credit
  /v1/service_items:
    get:
      tags:
        - Ítems de Servicio (LC 116)
      summary: Listar ítems de servicio
      description: Devuelve una lista paginada de los ítems de servicio (catálogo LC 116/2003) de la organización actual. Usa los filtros para restringir por empresa, código LC 116, NBS, clasificación tributaria, indicador de operación o anexo del Simples.
      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
            format: uuid
            description: Filtra por UUID de la empresa emisora asociada al ítem.
          required: false
          name: company_id
          in: query
        - schema:
            type: string
            description: Búsqueda textual libre en `name`, `internal_code` y `description`.
          required: false
          name: search
          in: query
        - schema:
            type: string
            enum:
              - "true"
              - "false"
            description: "Filtra por estado: `true` devuelve solo ítems activos; `false`, solo inactivos."
          required: false
          name: is_active
          in: query
        - schema:
            type: string
            description: Filtra por el código LC 116/2003 (p. ej. `01.05`).
          required: false
          name: lc116_code
          in: query
        - schema:
            type: string
            description: Filtra por el código NBS (Nomenclatura Brasileña de Servicios).
          required: false
          name: nbs_code
          in: query
        - schema:
            type: string
            description: Filtra por la clasificación tributaria IBS/CBS (`c_class_trib`).
          required: false
          name: c_class_trib
          in: query
        - schema:
            type: string
            description: Filtra por el Indicador de Operación (`indop_code`) usado en la NFS-e SNNFSE.
          required: false
          name: indop_code
          in: query
        - schema:
            type: string
            enum:
              - annex_iii
              - annex_iv
              - annex_v
            description: "Filtra por el anexo del Simples Nacional aplicable: `annex_iii`, `annex_iv` o `annex_v`."
          required: false
          name: simples_annex
          in: query
        - schema:
            type: string
            description: Filtra por el código CNAE relacionado con el servicio.
          required: false
          name: cnae_code
          in: query
        - schema:
            type: string
            description: Filtra por el código municipal del servicio.
          required: false
          name: municipal_code
          in: query
        - schema:
            type: string
            description: Filtra por el código interno del ítem.
          required: false
          name: internal_code
          in: query
        - schema:
            type: string
            description: Filtra por la categoría CBS/IBS del ítem según la reforma tributaria.
          required: false
          name: cbs_ibs_category
          in: query
        - schema:
            type: string
            format: date
            description: Inicio del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_after
          in: query
        - schema:
            type: string
            format: date
            description: Fin del rango de fecha de creación (YYYY-MM-DD).
            example: 2026-01-15
          required: false
          name: created_before
          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-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 ítems de servicio.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemListResponse"
        "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-service-items
    post:
      tags:
        - Ítems de Servicio (LC 116)
      summary: Crear ítem de servicio
      description: Crea un ítem de servicio en el catálogo LC 116/2003. `internal_code` es el identificador interno y `lc116_code` debe seguir el catálogo de la Ley Complementaria 116/2003 (p. ej. `01.05`). Cuando se informa `company_id`, la empresa debe pertenecer a la organización autenticada.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ServiceItemCreateRequest"
      responses:
        "201":
          description: Ítem de servicio creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemResponse"
        "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-service-items
      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-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:
        - Ítems de Servicio (LC 116)
      summary: Crear o actualizar ítem de servicio
      description: Recibe el mismo cuerpo del POST, más `id` y `public_id`, y deduplica por `id`, `public_id`, `external_id` y las claves naturales del recurso, en ese orden, deteniéndose en la primera que encuentre un registro. Si lo encuentra, lo actualiza y responde 200; si no, lo crea y responde 201. Los campos obligatorios del POST solo se exigen cuando no se encuentra ningún registro, y la actualización es parcial.
      security:
        - bearerAuth: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ServiceItemUpsertRequest"
      responses:
        "200":
          description: Registro actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemUpsertResponse"
        "201":
          description: Registro creado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemUpsertResponse"
        "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-service-items
      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-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/service_items/{id}:
    get:
      tags:
        - Ítems de Servicio (LC 116)
      summary: Obtener ítem de servicio
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de servicio.
          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-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 ítem de servicio.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemResponse"
        "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-service-items-id
    patch:
      tags:
        - Ítems de Servicio (LC 116)
      summary: Actualizar ítem de servicio
      description: Actualiza campos editables del ítem de servicio. `internal_code` es inmutable después de la creación. Usa `is_active=false` para desactivar el ítem sin eliminarlo.
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de servicio.
          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-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/ServiceItemUpdateRequest"
      responses:
        "200":
          description: Ítem de servicio actualizado.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServiceItemResponse"
        "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-service-items-id
    delete:
      tags:
        - Ítems de Servicio (LC 116)
      summary: Eliminar ítem de servicio
      description: Elimina el ítem de servicio permanentemente. Para preservar el historial en facturas o NFS-e ya emitidas, prefiere desactivar el ítem (`PATCH` con `is_active=false`).
      security:
        - bearerAuth: []
      parameters:
        - schema:
            type: string
            format: uuid
            description: UUID del ítem de servicio.
          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-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: Ítem de servicio 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: 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-service-items-id
  /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-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: 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-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-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: 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-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-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-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-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-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-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-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-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-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-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-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/portal_users:
    get:
      tags:
        - Administración de la Cuenta
      summary: Lista usuarios del portal
      description: Devuelve los usuarios del portal del cliente en la organización autenticada, 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
            format: uuid
            description: Restringe a una cuenta de cobro específica.
          required: false
          name: billing_account_id
          in: query
        - schema:
            type: string
            description: Restringe a todas las cuentas de cobro de un cliente. Acepta el `id` del cliente o su `external_id`.
          required: false
          name: customer_id
          in: query
        - schema:
            type: string
            enum:
              - active
              - pending_invitation
              - pending_verification
              - 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
        - 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-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/CustomerPortalUserListResponse"
        "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
webhooks: {}
