openapi: 3.0.3
info:
  title: TelcomNFe API
  version: 2.6.0
  description: >
    API REST para emissão de **NFCom (modelo 62)** e **NFS-e nacional**, e cadastro de destinatários e serviços.


    Use esta documentação se você integra um ERP, sistema de cobrança ou outro software

    ao TelcomNFe. O login na API não existe: o cliente gera um token no painel e o

    envia no header `Authorization`.


    ## URL da API


    Todas as chamadas usam o mesmo endereço:


    **`https://api.nfcom.telcomnfe.com.br`**


    Painel do cliente: [https://web.nfcom.telcomnfe.com.br](https://web.nfcom.telcomnfe.com.br)


    ## Como testar sem emitir nota real


    Não há uma URL de API separada para testes. O ambiente (SEFAZ **homologação** ou

    **produção**) é o da **empresa no painel**, em **Configurações → Ambiente NFCom**.


    Formas usuais de testar a integração:


    1. **Empresa de teste** — cadastre em
       [https://web.nfcom.telcomnfe.com.br/auth/test](https://web.nfcom.telcomnfe.com.br/auth/test)
       uma empresa só para a integração, com certificado de homologação e ambiente
       SEFAZ em homologação.
    2. **Empresa real em homologação SEFAZ** — use a empresa de produção, mas deixe
       o ambiente NFCom em **homologação** até validar o fluxo. Nesse modo o TelcomNFe
       aponta para o ambiente de **homologação da SEFAZ** (as notas não têm validade
       fiscal).

    Quando a integração estiver pronta, altere o ambiente da empresa para **produção**

    no painel (aí as emissões passam a ir para a SEFAZ de produção). A URL da API e o

    token continuam os mesmos.


    ## Autenticação


    Inclua o token em **todas** as requisições autenticadas:


    ```

    Authorization: Bearer {token}

    ```


    O token é gerado em **Configurações → Integração API**. Quem desenvolve a

    integração não faz login na API.


    ## Certificado digital


    Para transmitir à SEFAZ, a empresa precisa de um certificado A1 (`.pfx`) em

    **Configurações → Certificado Digital**. Sem certificado, a NFCom não é

    assinada nem enviada.


    Em testes, use o certificado de **homologação** da SEFAZ. Em operação, o de

    **produção**.


    Passo a passo na central de ajuda:

    <a href="https://telcomnfe.com.br/ajuda/certificado-digital" target="_blank" rel="noopener
    noreferrer">https://telcomnfe.com.br/ajuda/certificado-digital</a>


    ## Qual endpoint usar


    Na prática, quase toda integração usa **um** destes caminhos:


    ### 1. `POST /v2/invoices/nfcom/full` (recomendado)


    Endpoint padrão de integração. Você envia os dados do destinatário, dos serviços

    e da nota **num único payload**. O TelcomNFe:


    - cria ou atualiza o destinatário, se precisar

    - cria os serviços que ainda não existirem

    - coloca a NFCom na **fila** de transmissão à SEFAZ (quando `autoTransmit` está ativo)


    A resposta é rápida (`nfcom_id` + status inicial). A autorização da SEFAZ chega

    depois — acompanhe por **webhook** ou por `GET /v2/invoices/status`.


    Use este endpoint no volume normal (ERP, billing, lote).


    ### 2. `POST /v2/invoices`


    Só faz sentido se o destinatário e os serviços **já estiverem cadastrados** e

    você tiver os IDs (`client.id`, `items[].id`). O painel usa esse fluxo; em

    integrações novas o `/nfcom/full` costuma ser mais simples.


    ### Depois de criar


    1. Guarde o `nfcom_id` (e, se houver, a `externalReference`)

    2. Configure webhook em **Configurações → Webhooks** ou envie `notification_url`
       no payload
    3. Consulte `GET /v2/invoices/status` quando precisar confirmar o status manualmente


    Resumo:


    | Situação | Endpoint |

    |---|---|

    | Integração padrão (recomendado) | `POST /v2/invoices/nfcom/full` |

    | Já tem IDs de cliente e serviços | `POST /v2/invoices` |


    ## NFS-e


    A emissão de NFS-e segue o mesmo modelo, com endpoints próprios em `/v2/invoices/nfse`:


    | Situação | Endpoint |

    |---|---|

    | Emitir (cadastra tomador e serviço) | `POST /v2/invoices/nfse/full` |

    | Emitir várias de uma vez | `POST /v2/invoices/nfse/full/batch` |

    | Emitir sempre enfileirando (ignora `autoTransmit`) | `POST /v2/invoices/nfse/full/sync` |

    | Acompanhar a nota | `GET /v2/invoices/nfse/{id}` ou o webhook |

    | Consultar de novo na prefeitura | `POST /v2/invoices/nfse/{id}/refresh` |

    | Reenviar nota com erro | `POST /v2/invoices/nfse/{id}/retransmit` |

    | Listar notas (filtro por `status`) | `GET /v2/invoices/nfse` |

    | Serviços cadastrados | `GET /v2/invoices/nfse/services` |

    | Corrigir nota autorizada | `POST /v2/invoices/nfse/{id}/substitute` |

    | Cancelar | `POST /v2/invoices/nfse/{id}/cancel` |

    | XML / PDF | `GET /v2/invoices/nfse/{id}/xml` e `/pdf` |

    | XMLs de um período | `POST /v2/invoices/download-xml-async` com `documentType: nfse` |


    O ambiente (homologação ou produção) e a série da NFS-e vêm das configurações

    de NFS-e da empresa no painel. As configurações, a importação/cópia/exclusão de serviços e o

    cancelamento em massa são feitos só pelo painel (`403 SETTINGS_PANEL_ONLY` com o token de integração).


    ## Guia rápido da NFS-e


    1. No painel, em **Minha empresa**, confira o regime tributário (Simples Nacional). Em
       **Configurações → NFS-e**, preencha série, ambiente (comece em homologação) e envie o certificado A1.
    2. Em **Configurações → Integrações**, gere o token, cadastre a URL do webhook e escolha o
       **Serviço padrão da API**.
    3. Emita a primeira nota com o payload mínimo:


    ```bash

    curl -X POST https://api.nfcom.telcomnfe.com.br/v2/invoices/nfse/full \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "external_id": "pedido-1001",
        "client": { "document": "12345678909" },
        "items": [{ "valor": 109.00 }]
      }'
    ```

       - `competencia` vazia usa o mês atual; `codigo_servico` vazio usa o serviço padrão.
       - `client.name` só é obrigatório quando o tomador ainda não está cadastrado.
       - A resposta é `201` com o `id` da nota e `status: pending` (a transmissão segue na fila).
    4. Acompanhe pelo webhook (`nfse_authorized` ou `nfse_rejected`) ou por `GET /v2/invoices/nfse/{id}`.
       Use o `external_id` para não emitir a mesma nota duas vezes: repetir o mesmo envio devolve a
       nota já criada; o mesmo `external_id` com dados diferentes devolve `409 EXTERNAL_ID_CONFLICT`
       com o `id` da nota existente em `error.details.id`.
    5. Se a nota ficar em `pending_consult`, não retransmita: o sistema consulta a prefeitura de novo
       e manda o resultado final pelo webhook.

    ## Erros da NFS-e


    Todas as rotas `/v2/invoices/nfse` respondem erros no mesmo formato:


    ```json

    {
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "client.document é obrigatório.",
        "fields": [
          { "field": "client.document", "code": "required", "message": "client.document é obrigatório." }
        ]
      }
    }

    ```


    | HTTP | Quando |

    |---|---|

    | `400` | Corpo que não é JSON válido (`INVALID_JSON`) |

    | `401` | Token ausente, inválido ou revogado |

    | `403` | Módulo NFS-e desabilitado ou rota só do painel (`SETTINGS_PANEL_ONLY`) |

    | `404` | Nota, serviço ou rota não encontrada (`NOT_FOUND`) |

    | `409` | `external_id` já usado com dados diferentes (`error.details.id` traz a nota existente) |

    | `413` | Corpo acima de 10 MB (`PAYLOAD_TOO_LARGE`) |

    | `422` | Dados ou parâmetros inválidos (`VALIDATION_ERROR` com `fields`, `INVALID_PAGINATION`, `INVALID_STATUS`…)
    ou regra de negócio |

    | `429` | Limite de requisições (`Retry-After`) |

    | `503` | Serviço temporariamente indisponível; tente de novo |


    No lote (`/full/batch`), cada nota recusada traz o mesmo `error` e o mesmo `status_code` que teria

    sozinha.


    ## Eventos do webhook


    Cada mudança de status gera um evento. O corpo traz `event`, `message`, o objeto da nota

    (`nfse` ou `nfcom`) e, na NFS-e, um `event_id` único (repetido em todas as tentativas de entrega);

    `nfse.status` e `nfse.previous_status` mostram a transição.

    Contrato completo em **Webhooks (Implementação)**.


    **NFS-e**


    | Evento | Status | Quando |

    |---|---|---|

    | `nfse_created` | `draft` | Nota criada sem transmitir |

    | `nfse_pending` | `pending` | Nota na fila de transmissão |

    | `nfse_processing` | `processing` | DPS enviada, aguardando retorno |

    | `nfse_pending_consult` | `pending_consult` | A prefeitura recebeu a DPS mas não confirmou o resultado; o sistema
    consulta de novo sozinho. Não retransmita |

    | `nfse_authorized` | `authorized` | NFS-e autorizada |

    | `nfse_rejected` | `error` | Rejeitada pela prefeitura/SEFIN ou erro no envio |

    | `nfse_canceled` | `canceled` | NFS-e cancelada |

    | `nfse_cancellation_error` | `cancellation_error` | Falha no cancelamento |

    | `nfse_substituted` | `substituted` | Substituída por outra NFS-e |


    Eventos intermediários (`nfse_pending`, `nfse_processing`) podem não ser enviados quando a nota

    avança rápido; o evento final sempre é enviado, com `nfse.previous_status`.


    **NFCom**


    | Evento | Quando |

    |---|---|

    | `nfcom_created` | Nota criada |

    | `nfcom_submitting` | Enviando à SEFAZ |

    | `nfcom_submitted` | Autorizada pela SEFAZ (cStat 100; a nota fica em `SUBMITTED`). `nfcom_authorized` não é
    enviado |

    | `nfcom_rejected` | Rejeitada ou falha no envio |

    | `nfcom_pending_cancellation` | Cancelamento enfileirado |

    | `nfcom_cancelling` | Cancelando |

    | `nfcom_cancelled` | Cancelada |

    | `nfcom_cancellation_error` | Falha no cancelamento |


    Entrega: até 5 novas tentativas (5 min, 15 min, 30 min, 1 h e 3 h depois da anterior), cada

    uma com timeout de 30 s. Responda `2xx` para confirmar o recebimento.


    ## Status da NFCom


    | Status | Significado |

    |---|---|

    | `DRAFT` | Rascunho, ainda não enfileirada |

    | `PENDING_SUBMISSION` | Na fila para envio à SEFAZ |

    | `SUBMITTING` | Enviando |

    | `SUBMITTED` | Autorizada pela SEFAZ (cStat 100). É o status final de uma nota válida; não existe status
    `AUTHORIZED` |

    | `VALIDATED` | Validada, aguardando próximos passos |

    | `PENDING_CANCELLATION` | Cancelamento enfileirado |

    | `CANCELLING` | Cancelando na SEFAZ |

    | `CANCELLED` | Cancelada |

    | `REPLACED` | Substituída |

    | `SUBMISSION_ERROR` | Falha no envio |

    | `CANCELLATION_ERROR` | Falha no cancelamento |


    Somente NFCom em `DRAFT`, `SUBMISSION_ERROR` (equivalente a rejeitada/erro) podem ser alteradas.
  contact:
    name: TelcomNFe Support
    email: suporte@telcomnfe.com.br
    url: https://telcomnfe.com.br
  license:
    name: Proprietary
    url: https://telcomnfe.com.br
servers:
  - url: https://api.nfcom.telcomnfe.com.br
    description: TelcomNFe API
security:
  - BearerAuth: []
tags:
  - name: NFCom
    description: |
      Emissão, atualização e cancelamento de NFCom (modelo 62).

      Use `/v2/invoices/nfcom/full` nas integrações. O endpoint cria ou atualiza
      destinatário e serviços automaticamente a partir do payload.
  - name: NFS-e
    description: |
      Emissão, substituição e cancelamento da NFS-e nacional (DPS).

      Use `/v2/invoices/nfse/full` nas integrações. O endpoint cria ou atualiza
      o tomador e os serviços automaticamente a partir do payload.

      A empresa precisa ter o módulo NFS-e habilitado e as configurações de NFS-e
      preenchidas no painel (série, ambiente e regime tributário).
  - name: NFS-e Consultas
    description: >
      Listagem, detalhe, histórico e atualização da situação das NFS-e.


      | Status | Significado |

      |---|---|

      | `draft` | Rascunho, ainda não enfileirada |

      | `pending` | Na fila de transmissão |

      | `processing` | DPS enviada, aguardando retorno |

      | `pending_consult` | Prefeitura recebeu a DPS sem confirmar o resultado; consulta automática em andamento (não
      retransmita) |

      | `authorized` | NFS-e autorizada |

      | `error` | Rejeitada ou falha no envio |

      | `pending_cancellation` | Cancelamento enfileirado |

      | `cancelling` | Cancelando |

      | `canceled` | Cancelada |

      | `cancellation_error` | Falha no cancelamento |

      | `substituted` | Substituída por outra NFS-e |


      Só notas em `draft` ou `error` podem ser alteradas ou excluídas.
  - name: NFS-e Arquivos
    description: Download de XML e PDF (DANFS-e), download em lote e envio por e-mail.
  - name: NFCom Consultas
    description: Listagem, detalhe, status e logs das NFCom emitidas.
  - name: NFCom Arquivos
    description: Download de XML/PDF, URLs públicas e envio por e-mail.
  - name: Clientes
    description: Cadastro de destinatários das notas fiscais.
  - name: Serviços
    description: Cadastro de serviços de telecomunicação usados nas NFCom.
  - name: Webhooks
    description: |
      Notificações HTTP enviadas ao seu sistema quando o status de uma NFCom ou NFS-e muda.

      Configure a URL em **Configurações → Integrações** (a NFCom também aceita `notification_url`
      na criação da nota). Lista de eventos em **Eventos do webhook**; payload, headers e assinatura
      em **Webhooks (Implementação)**.
  - name: Webhooks (Implementação)
    description: |
      Contrato do endpoint que **o seu sistema** deve expor para receber as notificações.
      Não é uma rota da API TelcomNFe.
  - name: Sistema
    description: Verificação de disponibilidade da API (sem token).
x-tagGroups:
  - name: NFCom
    tags:
      - NFCom
      - NFCom Consultas
      - NFCom Arquivos
  - name: NFS-e
    tags:
      - NFS-e
      - NFS-e Consultas
      - NFS-e Arquivos
  - name: Cadastros
    tags:
      - Clientes
      - Serviços
  - name: Integração
    tags:
      - Webhooks
      - Webhooks (Implementação)
  - name: Disponibilidade
    tags:
      - Sistema
paths:
  /health:
    get:
      tags:
        - Sistema
      summary: Verificar disponibilidade
      description: |
        Confirma que a API está no ar. **Não exige token.**

        Útil para o integrador validar conectividade antes das demais chamadas.
      security: []
      responses:
        "200":
          description: API operacional
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
                  timestamp:
                    type: string
                    format: date-time
                    example: 2026-09-08T16:00:00.000Z
                  version:
                    type: string
                    example: 2.5.6
                  uptime:
                    type: number
                    description: Tempo de execução do processo em segundos
                    example: 86400
                  services:
                    type: object
                    properties:
                      api:
                        type: string
                        example: healthy
                      websocket:
                        type: string
                        example: healthy
  /v2/invoices/nfcom/full:
    post:
      tags:
        - NFCom
      summary: Criar NFCom Completa
      description: |
        **Endpoint de integração (recomendado).** Cria uma NFCom (modelo 62) com cadastro
        automático de cliente e serviços, e enfileira a transmissão à SEFAZ.

        A resposta retorna rápido com `nfcom_id` e o status inicial. Acompanhe a
        autorização da SEFAZ por **webhook** ou `GET /v2/invoices/status`.

        ### Funcionalidades
        - Cadastro ou atualização automática do destinatário
        - Cadastro automático de serviços inexistentes
        - Validação conforme MOC NFCom
        - `autoTransmit` (padrão `true`) controla se a nota vai para a fila de transmissão à SEFAZ
        - `notification_url` por nota tem prioridade sobre a URL das configurações
        - A **série** da NFCom vem das **Configurações** da empresa (não é enviada no payload)

        ### Webhook
        Informe `notification_url` no payload **ou** configure a URL padrão em
        **Configurações → Webhooks**. Documentação do payload: tag **Webhooks (Implementação)**.
      requestBody:
        required: true
        content:
          application/json:
            schema: &a2
              type: object
              required:
                - model
                - issue_date
                - issue_finality
                - client
                - items
              properties:
                external_reference: &a8
                  type: string
                  maxLength: 255
                  example: REF-EXTERNA-2024-001
                  description: Referência externa para integração (equivalente ao integration_id dos tax_receipts)
                notification_url:
                  type: string
                  format: uri
                  example: https://seu-sistema.com/webhook/nfcom-notifications
                  description: |
                    **URL de webhook para notificações desta NFCom (PRIORIDADE MÁXIMA)**

                    ⚠️ **IMPORTANTE**:
                    - Se informado, tem prioridade sobre a URL configurada no sistema
                    - Deve ser uma URL acessível via HTTP/HTTPS
                    - Receberá notificações de mudanças de status desta NFCom específica
                    - Se omitido, usará a URL das configurações do sistema (se configurada)

                    📚 **Documentação**: Veja o [Guia de Implementação de Webhooks](./WEBHOOK-IMPLEMENTATION-GUIDE.md)
                model: &a9
                  type: integer
                  enum:
                    - 62
                  example: 62
                  description: Modelo da nota fiscal (sempre 62 para NFCom)
                issue_date: &a10
                  type: string
                  format: date-time
                  example: 2024-08-21T10:30:00.000Z
                  description: |
                    Data/hora de emissão da nota fiscal (obrigatório).
                    Não pode ser futura nem anterior a **5 dias** da data atual.
                issue_finality: &a11
                  type: integer
                  enum:
                    - 0
                    - 3
                    - 4
                  example: 0
                  description: |
                    Finalidade de emissão:
                    - 0: Normal
                    - 3: Substituição
                    - 4: Ajuste
                substitute_reason: &a12
                  type: integer
                  enum:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                  example: 1
                  description: |
                    Motivo de substituição (obrigatório quando issue_finality = 3):
                    - 1: Erro de Preço
                    - 2: Erro Cadastral
                    - 3: Decisão Judicial
                    - 4: Erro de Tributação
                    - 5: Descontinuidade do Serviço
                prepaid_service_indicator: &a13
                  type: integer
                  enum:
                    - 0
                    - 1
                  default: 0
                  example: 0
                  description: |
                    Indicador de serviço pré-pago:
                    - 0: Não
                    - 1: Sim
                network_media_session_indicator: &a14
                  type: integer
                  enum:
                    - 0
                    - 1
                  default: 0
                  example: 0
                  description: |
                    Indicador de cessão de meios de rede:
                    - 0: Não
                    - 1: Sim
                reference_model: &a15
                  type: integer
                  example: 62
                  description: Modelo de referência (opcional)
                reference_month_year: &a16
                  type: string
                  example: "202408"
                  description: Mês/ano de referência (opcional)
                reference_series: &a17
                  type: string
                  example: "001"
                  description: Série de referência (opcional)
                reference_number: &a18
                  type: integer
                  example: 123
                  description: Número de referência (opcional)
                hash_convention_115: &a19
                  type: string
                  example: abc123
                  description: Hash convênio 115 (opcional)
                original_access_key: &a20
                  type: string
                  example: "35240812345678000123620010000001231234567890"
                  description: |
                    Chave de acesso da NFCom original (44 dígitos).
                    **Obrigatória** quando `issue_finality = 3` (substituição).
                observation: &a21
                  type: string
                  maxLength: 2000
                  example: Observações adicionais da nota fiscal
                  description: Observações da nota fiscal (máximo 2000 caracteres)
                service_description: &a22
                  type: string
                  example: Serviços de telecomunicações prestados no período
                  description: Descrição dos serviços (opcional)
                client: &a23
                  type: object
                  required:
                    - name
                    - document
                    - subscriber_type
                    - address
                  properties:
                    name:
                      type: string
                      minLength: 1
                      maxLength: 60
                      example: João da Silva Ltda
                      description: Nome do cliente (máximo 60 caracteres, conforme MOC NFCom)
                    document:
                      type: string
                      maxLength: 20
                      example: "12345678000190"
                      description: |
                        Documento do destinatário (obrigatório).
                        - Brasil: CPF (11) ou CNPJ (14, numérico ou alfanumérico), com ou sem máscara
                        - Estrangeiro (`abroad: true`): 2 a 20 caracteres ASCII válidos
                    ie:
                      type: string
                      example: "123456789012"
                      description: Inscrição Estadual (opcional)
                    im:
                      type: string
                      example: "12345"
                      description: Inscrição Municipal (opcional)
                    abroad:
                      type: boolean
                      default: false
                      example: false
                      description: |
                        `true` se o destinatário é estrangeiro (sem CPF/CNPJ brasileiro).
                        Quando `true`, informe `address.country_code` e `address.country_name`.
                    indicator_ie:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 9
                      example: 1
                      description: |
                        Indicador da Inscrição Estadual:
                        - 1: Contribuinte do ICMS
                        - 2: Contribuinte isento
                        - 9: Não contribuinte

                        **Obrigatório para CNPJ.** Para CPF ou `abroad: true`, o sistema usa `9`
                        automaticamente se omitido.
                    subscriber_code:
                      type: string
                      maxLength: 15
                      example: ASS-001
                      description: Código do assinante (opcional, máximo 15 caracteres)
                    subscriber_type:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 3
                        - 4
                        - 5
                        - 6
                        - 7
                        - 8
                        - 99
                      example: 1
                      description: |
                        Tipo de assinante (obrigatório):
                        - 1: Comercial
                        - 2: Industrial
                        - 3: Residencial/Pessoa Física
                        - 4: Produtor Rural
                        - 5: Órgão público estadual
                        - 6: Prestador de telecomunicações
                        - 7: Missões diplomáticas
                        - 8: Igrejas e Templos
                        - 99: Outros
                    usage_type:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 3
                        - 4
                        - 5
                        - 6
                        - 7
                      default: 7
                      example: 4
                      description: |
                        Tipo de utilização do serviço (opcional; padrão `7`):
                        - 1: Telefonia
                        - 2: Comunicação de Dados
                        - 3: TV por Assinatura
                        - 4: Provimento de acesso à Internet
                        - 5: Multimídia
                        - 6: Outros
                        - 7: Vários (NFCom modelo 62)
                    contract_number:
                      type: string
                      maxLength: 20
                      example: CONT-2024-001
                      description: Número do contrato (máximo 20 caracteres)
                    contract_start_date:
                      type: string
                      format: date-time
                      example: 2024-01-01T00:00:00.000Z
                      description: Data de início do contrato (opcional)
                    contract_end_date:
                      type: string
                      format: date-time
                      example: 2024-12-31T23:59:59.000Z
                      description: Data de fim do contrato (opcional; deve ser >= data inicial)
                    main_terminal_number:
                      type: string
                      example: "11987654321"
                      description: Número do terminal principal (opcional)
                    terminal_uf_code:
                      type: string
                      length: 2
                      example: SP
                      description: UF do terminal (2 caracteres, opcional)
                    address:
                      type: object
                      required:
                        - number
                      properties:
                        street:
                          type: string
                          maxLength: 255
                          example: Rua das Flores
                          description: Logradouro (obrigatório quando CEP não informado)
                        number:
                          type: string
                          maxLength: 60
                          example: "123"
                          description: Número do endereço (obrigatório)
                        complement:
                          type: string
                          maxLength: 255
                          example: Apto 45
                          description: Complemento do endereço (opcional, máximo 255 caracteres)
                        neighborhood:
                          type: string
                          maxLength: 255
                          example: Centro
                          description: Bairro (obrigatório quando CEP não informado)
                        city:
                          type: string
                          maxLength: 255
                          example: São Paulo
                          description: Cidade (obrigatório quando CEP não informado)
                        city_code:
                          type: string
                          length: 7
                          pattern: ^\\d{7}$
                          example: "3550308"
                          description: Código da cidade IBGE (7 dígitos, obrigatório quando CEP não informado)
                        uf:
                          type: string
                          length: 2
                          example: SP
                          description: UF (2 caracteres, obrigatório quando CEP não informado)
                        zip_code:
                          type: string
                          example: "01234567"
                          description: CEP (8 dígitos; aceita com ou sem máscara)
                        country_code:
                          type: integer
                          example: 2496
                          description: Código numérico do país (obrigatório quando `client.abroad = true`)
                        country_name:
                          type: string
                          example: Argentina
                          description: Nome do país (obrigatório quando `client.abroad = true`)
                    contacts:
                      type: object
                      properties:
                        email:
                          oneOf:
                            - type: string
                              format: email
                            - type: array
                              minItems: 1
                              maxItems: 10
                              uniqueItems: true
                              items:
                                type: string
                                format: email
                          example: cliente@exemplo.com
                          description: |
                            E-mail de contato. Aceita string única ou array (máximo 10, sem duplicados).
                            Necessário para envio automático da DANFE/XML.
                        phone:
                          type: string
                          maxLength: 20
                          example: "11987654321"
                          description: Telefone de contato (opcional)
                items: &a24
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - description
                      - classification_code
                      - unity
                      - quantity
                      - unit_value
                    properties:
                      code:
                        type: string
                        maxLength: 60
                        example: INET200
                        description: Código do item/serviço (opcional, máximo 60 caracteres)
                      description:
                        type: string
                        maxLength: 120
                        example: Internet Banda Larga 200MB
                        description: Descrição do item/serviço (obrigatório, máximo 120 caracteres)
                      classification_code:
                        type: string
                        example: "0400401"
                        description: >
                          Código de classificação de serviços NFCom (obrigatório, cClass). Código fora da tabela de

                          classificação da NFCom (tabela cClass do portal SVRS, ex.: 9999999) volta com 400 antes de
                          transmitir.

                          Principais códigos para NFCom modelo 62:


                          010 - Assinatura:

                          - 0100101: Assinatura de serviços de telefonia

                          - 0100201: Assinatura de serviços de comunicação de dados

                          - 0100301: Assinatura de serviços de TV por Assinatura

                          - 0100401: Assinatura de serviços de comunicação multimídia


                          020 - Habilitação:

                          - 0200101: Habilitação de serviços de telefonia

                          - 0200201: Habilitação de serviços de comunicação de dados

                          - 0200301: Habilitação de TV por Assinatura


                          030 - Serviço Medido:

                          - 0300101: Chamadas locais

                          - 0300102: Chamadas longa distância nacional

                          - 0300103: Chamadas longa distância internacionais

                          - 0300108: Mensagem SMS

                          - 0300201: Comunicação de dados

                          - 0300401: Comunicação multimídia


                          040 - Serviço Não Medido:

                          - 0400101: Telefonia

                          - 0400201: Comunicação de dados

                          - 0400301: TV por Assinatura

                          - 0400401: Provimento à internet

                          - 0400501: Comunicação multimídia


                          045 - Serviços Combinados:

                          - 0450101: Serviços Combinados (dados, voz, mensagens e outros)


                          050 - Serviço Pré-pago:

                          - 0500101: Cartão Telefônico - Telefonia Fixa

                          - 0500201: Carga / Recarga de Créditos - Telefonia Móvel

                          - 0500301: Carga / Recarga de Créditos - Serviço de Comunicação Multimídia


                          060 - Outros Serviços:

                          - 0600101: Facilidades Adicionais

                          - 0600201: Streaming de vídeo e áudio

                          - 0600301: Serviço de Rastreamento

                          - 0600501: Outros Serviços (instalação, software, visita técnica, etc.)


                          070 - Cessão Meios de Rede:

                          - 0700101: Interconexão

                          - 0700201: Roaming

                          - 0700301: Exploração Industrial de Linha Dedicada - EILD


                          080 - Disponibilização de Equipamentos:

                          - 0800301: Modem

                          - 0800601: Roteador

                          - 0800701: Servidor

                          - 0800901: Decodificador/Conversor

                          - 0801001: Outros equipamentos


                          100 - Cobrança Própria:

                          - 1000301: Cobrança de juros de mora

                          - 1000401: Cobrança de multa de mora

                          - 1000501: Cobrança de conta de meses anteriores


                          590 - Deduções:

                          - 5900101: Dedução relativa a impugnação de serviços

                          - 5900201: Dedução referente ajuste de conta

                          - 5900501: Outras deduções
                      cfop:
                        type: string
                        nullable: true
                        pattern: ^\\d{4}$
                        example: "5307"
                        description: |
                          CFOP (4 dígitos). Pode ser omitido ou `null` em grupos especiais
                          (050, 100, 110, 120, 130, 590 — exceto mercadorias 1000901/1100901).

                          Principais códigos para telecomunicações:

                          Operações dentro do estado:
                          - 5301 a 5307: Prestação de serviço de comunicação
                          - 5933: Prestação tributada pelo ISSQN

                          Operações interestaduais: 6301 a 6307
                          Operações com exterior: 7301
                      unity:
                        type: integer
                        enum:
                          - 1
                          - 2
                          - 3
                          - 4
                        example: 1
                        description: |
                          Unidade básica de medida (`uMed` no XML NFCom). Valores permitidos:
                          - `1` — Minuto
                          - `2` — MB (Megabyte)
                          - `3` — GB (Gigabyte)
                          - `4` — UN (Unidade)
                      quantity:
                        type: number
                        minimum: 0.01
                        example: 1
                        description: Quantidade (maior que zero, obrigatório)
                      unit_value:
                        type: number
                        minimum: 0
                        example: 129.9
                        description: |
                          Valor unitário do item (obrigatório). Pode ser `0`; valores negativos
                          não são aceitos.
                      discount_value:
                        type: number
                        minimum: 0
                        example: 10
                        description: |
                          Valor de desconto (opcional, vDesc). Não pode ser maior que
                          `unit_value × quantity + other_expenses`: a requisição volta com 400 antes de transmitir.
                      other_expenses:
                        type: number
                        minimum: 0
                        example: 5
                        description: |
                          Outras despesas acessórias do item (opcional, vOutro). Vão para o XML e são cobradas:
                          vProd do item = `unit_value × quantity − discount_value + other_expenses` (MOC G86),
                          o vOutro do total é a soma dos itens e o vNF parte do vProd. As bases de ICMS, PIS/COFINS
                          e FUST/FUNTTEL incluem as outras despesas. Ex.: unitário 100, desconto 10 e despesas 5
                          geram vDesc 10,00, vOutro 5,00, vProd 95,00 e base do ICMS 95,00. Nos itens com outras
                          despesas, as retenções (vRetPIS, vRetCofins, vRetCSLL, vIRRF) e o vBCIRRF também partem do
                          vProd: unitário 100, desconto 104 e despesas 5 geram vProd 1,00 e vBCIRRF 1,00. Itens sem
                          outras despesas não mudam.
                      icms_cst:
                        type: string
                        enum:
                          - "00"
                          - "10"
                          - "20"
                          - "30"
                          - "40"
                          - "41"
                          - "50"
                          - "51"
                          - "60"
                          - "70"
                          - "90"
                        example: "00"
                        description: |
                          CST do ICMS (opcional). Valores aceitos:
                          `00`, `10`, `20`, `30`, `40`, `41`, `50`, `51`, `60`, `70`, `90`.
                      icms_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 18
                        description: Alíquota do ICMS (0-100%). Ausente usa a configuração da empresa; 0 informado segue a regra do CST (CST 00
                          exige alíquota maior que zero).
                      icms_bc_reduction:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 0
                        description: Redução da BC do ICMS (0-100%)
                      icms_interstate_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        nullable: true
                        example: 12
                        description: Alíquota interestadual do ICMS (0-100%, opcional)
                      fcp_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 2
                        description: Alíquota do FCP (0-100%)
                      fiscal_benefit_code:
                        type: string
                        example: PR123456
                        description: Código de benefício fiscal (opcional)
                      destination_fcp_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 2
                        description: Alíquota FCP destino (0-100%)
                      destination_internal_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 18
                        description: Alíquota interna destino (0-100%)
                      destination_fiscal_benefit_code:
                        type: string
                        example: SP789012
                        description: Código benefício fiscal destino (opcional)
                      pis_cst:
                        type: string
                        enum:
                          - "01"
                          - "02"
                          - "06"
                          - "07"
                          - "08"
                          - "09"
                          - "49"
                        example: "01"
                        description: |
                          CST do PIS (opcional):
                          - 01: Tributável com alíquota básica
                          - 02: Tributável com alíquota diferenciada
                          - 06: Tributável com alíquota zero
                          - 07: Operação isenta de contribuição
                          - 08: Operação sem incidência da contribuição
                          - 09: Operação com suspensão da contribuição
                          - 49: Outras operações de saída
                      pis_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 1.65
                        description: Alíquota do PIS (0-100%). Com CST 01/02, 0 ou ausente usa a alíquota da configuração da empresa; `null`
                          também, exceto no `PUT` e no `PATCH`, que retornam 400. Para emitir 0 de verdade, envie
                          `aliquota_zero`.
                      cofins_cst:
                        type: string
                        enum:
                          - "01"
                          - "02"
                          - "06"
                          - "07"
                          - "08"
                          - "09"
                          - "49"
                        example: "01"
                        description: |
                          CST do COFINS (opcional):
                          - 01: Tributável com alíquota básica
                          - 02: Tributável com alíquota diferenciada
                          - 06: Tributável com alíquota zero
                          - 07: Operação isenta de contribuição
                          - 08: Operação sem incidência da contribuição
                          - 09: Operação com suspensão da contribuição
                          - 49: Outras operações de saída
                      cofins_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 7.6
                        description: Alíquota do COFINS (0-100%). Com CST 01/02, 0 ou ausente usa a alíquota da configuração da empresa; `null`
                          também, exceto no `PUT` e no `PATCH`, que retornam 400. Para emitir 0 de verdade, envie
                          `aliquota_zero`.
                      fust_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 1
                        description: Alíquota do FUST (0-100%). Ausente usa a alíquota da configuração da empresa; `null` também, exceto no
                          `PUT` e no `PATCH`, que retornam 400. O `0` depende da rota - no `POST /full` usa a
                          configuração; na `/full/sync`, no `PUT` e no `PATCH` é gravado como 0. Para emitir 0 em
                          qualquer rota, envie `aliquota_zero`.
                      funttel_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 0.5
                        description: Alíquota do FUNTTEL (0-100%). Ausente usa a alíquota da configuração da empresa; `null` também, exceto no
                          `PUT` e no `PATCH`, que retornam 400. O `0` depende da rota - no `POST /full` usa a
                          configuração; na `/full/sync`, no `PUT` e no `PATCH` é gravado como 0. Para emitir 0 em
                          qualquer rota, envie `aliquota_zero`.
                      aliquota_zero: &a6
                        oneOf:
                          - type: boolean
                          - type: array
                            uniqueItems: true
                            items:
                              type: string
                              enum:
                                - pis
                                - cofins
                                - fust
                                - funttel
                        nullable: true
                        default: false
                        example:
                          - pis
                          - cofins
                        description: >
                          Pedido explícito de alíquota 0 (opcional, desligado por padrão). Vale igual em `/full`,
                          `/full/sync`, `PUT`, `PATCH` e na rota legada (`/v2/invoices/nfcom/legacy/create`).


                          **Sem este campo**, vale a regra de cada rota:


                          | Tributo / valor enviado | `POST /full` | `/full/sync` | `PUT` e `PATCH` |

                          |---|---|---|---|

                          | PIS e COFINS (CST 01/02): `0` ou ausente | usa a configuração | usa a configuração | usa a
                          configuração |

                          | FUST e FUNTTEL: `0` | usa a configuração | gravado como 0 | gravado como 0 |

                          | FUST e FUNTTEL: ausente | usa a configuração | usa a configuração | usa a configuração |

                          | Qualquer alíquota (ICMS, PIS, COFINS, FUST, FUNTTEL): `null` | usa a configuração | usa a
                          configuração | 400 (`deve ser um número`) |


                          A diferença do `null` entre as rotas é a mesma da versão em produção e foi mantida para não
                          mudar o comportamento de quem já integra.


                          **Com ele**, os tributos pedidos saem com alíquota e valor 0, com a alíquota enviada como `0`
                          ou sem o campo:


                          - `true`: PIS, COFINS, FUST e FUNTTEL.

                          - lista (`["pis", "cofins"]`): só os tributos listados. Aceita `pis`, `cofins`, `fust` e
                          `funttel`.


                          Tributo pedido com alíquota maior que 0 no mesmo item retorna 400 (conflito). O ICMS não entra
                          neste campo: o ICMS 0 segue a regra do CST. Com CST 00 (ou 20), `icms_rate: 0` retorna 400 em
                          todas as rotas; para usar a alíquota da configuração omita o campo, e para ICMS sem tributação
                          use CST 40, 41 ou 51.


                          Alíquota enviada como texto vazio (`""`) retorna 400 (`deve ser um número`); para usar a
                          configuração, omita o campo ou envie `0` (ou `null`, aceito em `POST /full` e `/full/sync`; no
                          `PUT` e no `PATCH` o `null` retorna 400).


                          Toda vez que um `0` é trocado pela configuração (sem este campo), o sistema registra em log a
                          empresa, a nota, o item, o tributo e a alíquota aplicada, para acompanhamento.
                      withheld_irrf_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 1.5
                        description: Alíquota IRRF retido (0-100%)
                      withheld_pis_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 0.65
                        description: Alíquota PIS retido (0-100%)
                      withheld_cofins_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 3
                        description: Alíquota COFINS retido (0-100%)
                      withheld_csll_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 1
                        description: Alíquota CSLL retido (0-100%)
                      municipal_tax_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 5
                        description: Alíquota tributo municipal (0-100%)
                      state_tax_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 2
                        description: Alíquota tributo estadual (0-100%)
                      federal_tax_rate:
                        type: number
                        minimum: 0
                        maximum: 100
                        example: 1
                        description: Alíquota tributo federal (0-100%)
                      ld_operator_cnpj:
                        type: string
                        pattern: ^\\d{14}$
                        example: "12345678000190"
                        description: CNPJ do operador LD (14 dígitos apenas números)
                      credit_expiration_date:
                        type: string
                        format: date-time
                        example: 2024-12-31T23:59:59.000Z
                        description: Data de expiração do crédito (opcional)
                      without_cst_cfop:
                        type: boolean
                        default: false
                        example: false
                        description: |
                          Se `true`, o item é emitido sem CST/CFOP (grupos especiais de classificação).
                          O sistema também aplica isso automaticamente para classificações 050/100/110/120/130/590.
                  description: Lista de serviços/produtos da NFCom (mínimo 1 item)
                billing_info: &a25
                  type: object
                  properties:
                    billing_type:
                      type: integer
                      enum:
                        - 0
                        - 1
                        - 2
                      default: 0
                      example: 0
                      description: |
                        Tipo de faturamento:
                        - 0: Faturamento Normal
                        - 1: Faturamento Centralizado
                        - 2: Cofaturamento
                    competence:
                      type: string
                      pattern: ^\\d{6}$
                      example: "202408"
                      description: Competência YYYYMM (obrigatório para faturamento normal)
                    due_date:
                      type: string
                      format: date-time
                      example: 2024-09-21T23:59:59.000Z
                      description: Data de vencimento (obrigatório para faturamento normal)
                    usage_period_start:
                      type: string
                      format: date-time
                      example: 2024-08-01T00:00:00.000Z
                      description: Data inicial do período (obrigatório para faturamento normal)
                    usage_period_end:
                      type: string
                      format: date-time
                      example: 2024-08-31T23:59:59.000Z
                      description: Data final do período (obrigatório para faturamento normal)
                    barcode:
                      type: string
                      maxLength: 54
                      example: "34191090080000012690001234567890123456789012"
                      description: Código de barras do boleto/fatura (44 dígitos) ou linha digitável (47 ou 48 dígitos); vai para codBarras no
                        XML. O DANFE-COM calcula e imprime a linha digitável formatada a partir deste campo (47 dígitos
                        para boleto bancário, 48 para arrecadação/convênio, iniciados por 8). Se o código não for
                        válido, a linha não é impressa. Máximo 54 caracteres.
                    pix_url:
                      type: string
                      maxLength: 2000
                      example: https://pix.example.com/qr/abc123
                      description: URL/texto do PIX (máximo 2000 caracteres)
                    bank_code:
                      type: string
                      length: 3
                      pattern: ^\\d{3}$
                      example: "341"
                      description: Código do banco (3 dígitos)
                    branch_code:
                      type: string
                      maxLength: 10
                      example: "1234"
                      description: Código da agência (máximo 10 caracteres)
                    bank_slip:
                      type: string
                      maxLength: 1000
                      example: "01234567890123456"
                      description: "Código de autorização do débito automático em conta (codDebAuto no layout da SEFAZ, numérico, até 20
                        dígitos). Apesar do nome, NÃO é o boleto nem a linha digitável: para boleto use `barcode`, de
                        onde a linha digitável é gerada. No DANFE-COM aparece no quadro \"Débito automático\"."
                    credit_debit_card:
                      type: string
                      maxLength: 1000
                      example: Informações do cartão de crédito/débito
                      description: Informações do cartão (máximo 1000 caracteres)
                    other_methods:
                      type: string
                      maxLength: 1000
                      example: Outros métodos de pagamento aceitos
                      description: Outros métodos de pagamento (máximo 1000 caracteres)
                    centralized_company_cnpj:
                      type: string
                      pattern: ^\\d{14}$
                      example: "12345678000190"
                      description: CNPJ da empresa centralizadora (14 dígitos, obrigatório para faturamento centralizado)
                    centralized_company_uf:
                      type: string
                      length: 2
                      enum:
                        - AC
                        - AL
                        - AP
                        - AM
                        - BA
                        - CE
                        - DF
                        - ES
                        - GO
                        - MA
                        - MT
                        - MS
                        - MG
                        - PA
                        - PB
                        - PR
                        - PE
                        - PI
                        - RJ
                        - RN
                        - RS
                        - RO
                        - RR
                        - SC
                        - SP
                        - SE
                        - TO
                      example: SP
                      description: UF da empresa centralizadora (2 caracteres, obrigatório para faturamento centralizado)
                    nfcom_local_key:
                      type: string
                      length: 44
                      pattern: ^\\d{44}$
                      example: "35240812345678000123620010000001231234567890"
                      description: Chave da NFCom local (44 dígitos, obrigatório para cofaturamento)
                    correspondence_address_type:
                      type: string
                      enum:
                        - client
                        - none
                        - custom
                      default: none
                      example: none
                      description: |
                        Tipo de endereço de correspondência:
                        - client: Utilizar endereço do destinatário
                        - none: Não informar endereço de correspondência
                        - custom: Informar endereço diferente
                    correspondence_street:
                      type: string
                      maxLength: 255
                      example: Rua da Correspondência
                      description: Logradouro (obrigatório quando `correspondence_address_type = custom`)
                    correspondence_number:
                      type: string
                      maxLength: 10
                      example: "100"
                      description: Número (obrigatório quando `correspondence_address_type = custom`)
                    correspondence_neighborhood:
                      type: string
                      maxLength: 100
                      example: Centro
                      description: Bairro (obrigatório quando `correspondence_address_type = custom`)
                    correspondence_city:
                      type: string
                      maxLength: 100
                      example: São Paulo
                      description: Cidade (obrigatória quando `correspondence_address_type = custom`)
                    correspondence_uf:
                      type: string
                      length: 2
                      example: SP
                      description: UF (obrigatória quando `correspondence_address_type = custom`)
                    correspondence_zip_code:
                      type: string
                      example: "01001000"
                      description: CEP (obrigatório quando `correspondence_address_type = custom`; 8 dígitos)
                    correspondence_complement:
                      type: string
                      maxLength: 100
                      example: Sala 789
                      description: Complemento da correspondência (opcional)
                    correspondence_phone:
                      type: string
                      pattern: ^\\d{7,14}$
                      example: "11987654321"
                      description: Telefone da correspondência (7-14 dígitos, opcional)
                    correspondence_email:
                      type: string
                      format: email
                      maxLength: 60
                      example: correspondencia@exemplo.com
                      description: E-mail da correspondência (máximo 60 caracteres, opcional)
                  description: Informações de faturamento (opcional)
                autoTransmit: &a26
                  type: boolean
                  default: true
                  example: true
                  description: |
                    Se `true` (padrão), a NFCom é enfileirada para transmissão à SEFAZ.
                    Se `false`, a nota permanece em rascunho (`DRAFT`) até uma transmissão posterior.
                emailNotificationAttachments: &a27
                  type: array
                  minItems: 1
                  uniqueItems: true
                  items:
                    type: string
                    enum:
                      - danfe
                      - xml
                  example:
                    - danfe
                    - xml
                  description: |
                    Se informado, após a autorização a DANFE/XML é enviada por e-mail ao destinatário.
                    Deve conter pelo menos um item: `danfe` (PDF) e/ou `xml`.
            examples: &a3
              example_nfcom_requered:
                summary: NFCom - Dados mínimos requeridos
                description: Exemplo de criação de NFCom com os dados mínimos requeridos
                value:
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    indicator_ie: 9
                    subscriber_type: 1
                    address:
                      number: "935"
                      zip_code: 09015-660
                  items:
                    - code: INET100
                      description: Internet Banda Larga 100MB
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 89.9
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-08-26
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
              exemplo_nfcom_normal:
                summary: NFCom com faturamento normal
                description: Exemplo de criação de NFCom com faturamento normal, incluindo todos os campos obrigatórios e opcionais
                  principais
                value:
                  external_reference: REF-EXTERNA-2025-001
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: Serviços de telecomunicações prestados no período de Agosto/2025
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 1
                    contract_number: CONT-2025-001
                    contract_start_date: 2025-01-01
                    main_terminal_number: "11999887766"
                    terminal_uf_code: SP
                    address:
                      street: Travessa Mariana Lotto
                      number: "720"
                      complement: Apto 45
                      neighborhood: Centro
                      city: São Bernardo do Campo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "09710070"
                    contacts:
                      email: joao.santos@email.com
                      phone: "11999887766"
                  items:
                    - code: INET100
                      description: Internet Banda Larga 100MB
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 89.9
                      discount_value: 5
                      other_expenses: 2
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-08-26
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
                    barcode: "34195175152345678712834123456005110185000002603"
                    pix_url: https://pix.banco.com.br/qr/v2/cobv/4f9e...
                    bank_code: "341"
                    branch_code: "1234"
                    bank_slip: "01234567890123456"
                    correspondence_address_type: client
              exemplo_nfcom_substituicao:
                summary: NFCom de substituição
                description: Exemplo de NFCom de substituição com referência à nota original
                value:
                  external_reference: REF-SUBSTITUICAO-2025-002
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 3
                  substitute_reason: 1
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  reference_model: 62
                  reference_month_year: "202508"
                  reference_series: "1"
                  reference_number: 123
                  original_access_key: "35240812345678000123620010000001231234567890"
                  observation: NFCom de substituição - correção de dados
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    ie: "123456789012"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 1
                    contract_number: CONT-PJ-2025-002
                    contract_start_date: 2025-06-01
                    main_terminal_number: "11888776655"
                    terminal_uf_code: SP
                    address:
                      street: Travessa Mariana Lotto
                      number: "720"
                      complement: Apto 45
                      neighborhood: Centro
                      city: São Bernardo do Campo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "09710070"
                    contacts:
                      email: contato@mariaempresa.com.br
                      phone: "1133334444"
                  items:
                    - code: INET500
                      description: Internet Banda Larga 500MB Empresarial
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 299.9
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      icms_bc_reduction: 0
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-09-25
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
                    pix_url: https://pix.banco.com.br/qr/v2/cobv/5g8f...
                    bank_code: "237"
                    correspondence_address_type: custom
                    correspondence_street: Rua da Correspondência
                    correspondence_number: "456"
                    correspondence_neighborhood: Jardim América
                    correspondence_city: São Paulo
                    correspondence_uf: SP
                    correspondence_zip_code: "01234567"
                    correspondence_email: financeiro@mariaempresa.com.br
                    correspondence_phone: "1144445555"
              exemplo_nfcom_centralizado:
                summary: NFCom com faturamento centralizado
                description: Exemplo de NFCom com faturamento centralizado por empresa matriz
                value:
                  external_reference: REF-2025-003
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: Faturamento centralizado - Filial Norte
                  client:
                    name: Empresa Filial Norte Ltda
                    document: "98765432000188"
                    ie: "987654321098"
                    indicator_ie: 1
                    subscriber_type: 2
                    usage_type: 3
                    contract_number: CONT-2025-003
                    contract_start_date: 2025-05-15
                    main_terminal_number: "11777665544"
                    terminal_uf_code: SP
                    address:
                      street: Rua do Comércio
                      number: "789"
                      neighborhood: Vila Industrial
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "04567890"
                    contacts:
                      email: filial.norte@empresa.com.br
                      phone: "1155556666"
                  items:
                    - code: VOIP200
                      description: VOIP Empresarial 200 ramais
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 1500
                      discount_value: 100
                      other_expenses: 50
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 1
                    centralized_company_cnpj: "12345678000100"
                    centralized_company_uf: SP
                    correspondence_address_type: none
              exemplo_nfcom_cofaturamento:
                summary: NFCom com cofaturamento
                description: Exemplo de NFCom com cofaturamento referenciando outra NFCom
                value:
                  external_reference: REF-COFAT-2025-004
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: NFCom de cofaturamento
                  client:
                    name: Empresa Parceira Ltda
                    document: "11223344000155"
                    ie: "112233445566"
                    indicator_ie: 1
                    subscriber_type: 2
                    usage_type: 4
                    contract_number: CONT-COFAT-2025-004
                    contract_start_date: 2025-07-01
                    main_terminal_number: "11666555444"
                    terminal_uf_code: SP
                    address:
                      street: Av. das Nações
                      number: "1500"
                      complement: Torre A
                      neighborhood: Brooklin
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "04578000"
                    contacts:
                      email: parceria@empresa.com.br
                      phone: "1199998888"
                  items:
                    - code: INFRA100
                      description: Compartilhamento de Infraestrutura
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 800
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 2
                    nfcom_local_key: "35240812345678000123620010000001001234567890"
                    correspondence_address_type: none
              exemplo_nfcom_prepago:
                summary: NFCom de serviço pré-pago
                description: Exemplo de NFCom para serviços pré-pagos (não requer informações de faturamento)
                value:
                  external_reference: REF-PREPAGO-2025-005
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 1
                  network_media_session_indicator: 0
                  observation: Recarga de créditos - serviço pré-pago
                  client:
                    name: Carlos Alberto Pereira
                    document: "98765432100"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 5
                    contract_number: PREP-2025-005
                    contract_start_date: 2025-08-23
                    main_terminal_number: "11987654321"
                    terminal_uf_code: SP
                    address:
                      street: Rua dos Trabalhadores
                      number: "456"
                      neighborhood: Vila Nova
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "03456789"
                    contacts:
                      email: carlos.pereira@email.com
                      phone: "11987654321"
                  items:
                    - code: CRED30
                      description: Créditos R$ 30,00
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 30
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
      responses:
        "201":
          description: NFCom criada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: NFCom criada com sucesso
                  data:
                    type: object
                    properties:
                      nfcom_id:
                        type: string
                        format: uuid
                        description: ID único da NFCom criada
                        example: 123e4567-e89b-12d3-a456-426614174000
                      series:
                        type: string
                        description: Série da NFCom
                        example: "1"
                      issue_date:
                        type: string
                        format: date-time
                        description: Data de emissão
                        example: 2025-09-01T10:30:00.000Z
                      status:
                        type: string
                        description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                          retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a
                          SEFAZ). Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais;
                          PENDING_SUBMISSION na fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada
                          ou com erro no envio; PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED
                          cancelada; CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED
                          substituída por outra NFCom."
                        enum:
                          - DRAFT
                          - PENDING_SUBMISSION
                          - SUBMITTING
                          - SUBMITTED
                          - VALIDATED
                          - PENDING_CANCELLATION
                          - CANCELLING
                          - CANCELLED
                          - REPLACED
                          - SUBMISSION_ERROR
                          - CANCELLATION_ERROR
                        example: PENDING_SUBMISSION
                      total_value:
                        type: number
                        format: decimal
                        description: Valor total da NFCom
                        example: 150.75
                      environment:
                        type: string
                        description: Ambiente de emissão (produção ou homologação)
                        enum:
                          - producao
                          - homologacao
                        example: homologacao
        "400":
          description: Dados inválidos
          content:
            application/json:
              schema: &a1
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: Dados inválidos fornecidos
                  errors:
                    type: array
                    items:
                      type: object
                      properties:
                        field:
                          type: string
                          example: client.document
                        message:
                          type: string
                          example: CPF/CNPJ inválido
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: &a4
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: Token de autenticação inválido ou expirado
        "422":
          description: Erro de validação
          content:
            application/json:
              schema: *a1
        "500":
          description: Erro interno do servidor
          content:
            application/json:
              schema: &a5
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: Erro interno do servidor
                  details:
                    type: string
                    description: Detalhes do erro (apenas em desenvolvimento)
                    example: Database connection failed
  /v2/invoices/nfcom/full/sync:
    post:
      tags:
        - NFCom
      summary: Criar e transmitir NFCom (síncrono)
      description: |
        Cria a NFCom e transmite à SEFAZ **na mesma requisição**. O payload é o mesmo de
        `POST /v2/invoices/nfcom/full`.

        Use este endpoint quando o integrador precisa da chave de acesso e do status
        imediatamente. Para alto volume, prefira o endpoint assíncrono
        (`POST /v2/invoices/nfcom/full`) e acompanhe por webhook.

        ### Diferenças em relação ao endpoint assíncrono

        | | `/full` | `/full/sync` |
        |---|---|---|
        | Transmissão | Enfileirada | Imediata |
        | Tempo de resposta | Rápido (aceite) | Depende da SEFAZ |
        | Resposta | `nfcom_id` + status inicial | Inclui `nfeKey` se autorizada |

        Alíquotas: PIS e COFINS (CST 01/02) com `0`, `null` ou ausentes usam a configuração da empresa.
        Diferente do `/full`, FUST e FUNTTEL enviados como `0` são gravados como 0; `null` ou ausentes usam a
        configuração. Com `aliquota_zero` no item, os tributos pedidos saem com 0.

        ### Repetição após timeout (504)

        Se a resposta não chegar (por exemplo, 504 do proxy), a nota pode ter sido criada e transmitida.
        Consulte por `external_reference` antes de repetir. Repetir com o mesmo `external_reference`
        não cria outra nota: retorna 400 (`NFCom já emitida com esta referência externa`, com o `id`) ou,
        se a primeira chamada ainda estiver em andamento, 409.

        Requisitos: certificado A1 configurado e ambiente (produção/homologação) definido no painel.
      requestBody:
        required: true
        content:
          application/json:
            schema: *a2
            examples: *a3
      responses:
        "201":
          description: NFCom criada (transmissão pode ter sido autorizada ou ter falhado)
          content:
            application/json:
              schema: &a7
                type: object
                description: |
                  Resposta no formato legado (compatível com tax_receipts), incluindo
                  o resultado da transmissão quando ela ocorre na mesma requisição.
                properties:
                  id:
                    type: string
                    format: uuid
                    description: ID da NFCom criada
                  number:
                    type: string
                    description: Número atribuído (pode ser vazio até a numeração)
                  series:
                    type: string
                    example: "1"
                  model:
                    type: integer
                    example: 62
                  issue_date:
                    type: string
                    format: date-time
                  amount:
                    type: number
                    example: 89.9
                  customer_id:
                    type: string
                    format: uuid
                  transmitted:
                    type: boolean
                    description: true se a transmissão à SEFAZ foi concluída nesta requisição
                    example: true
                  nfeKey:
                    type: string
                    description: Chave de acesso (44 dígitos), presente se autorizada
                    example: "35240514200166000187620010000001231234567890"
                  status:
                    type: string
                    example: SUBMITTED
                  transmissionMessage:
                    type: string
                    example: NFCom transmitida com sucesso para a SEFAZ
                  url_pdf:
                    type: string
                    format: uri
                    description: URL do PDF quando gerado
        "400":
          description: Dados inválidos
          content:
            application/json:
              schema: *a1
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a4
        "409":
          description: Já existe uma emissão em andamento com o mesmo `external_reference`
        "422":
          description: Erro de validação
          content:
            application/json:
              schema: *a1
        "500":
          description: Erro interno
          content:
            application/json:
              schema: *a5
  /v2/invoices/nfcom/legacy/create:
    post:
      tags:
        - NFCom
      summary: Criar e transmitir NFCom no formato legado (síncrono)
      description: >
        Recebe o mesmo formato da antiga rota `/taxReceipts/create` (NF-21/NF-22), converte para NFCom e

        transmite à SEFAZ **na mesma requisição**, como `POST /v2/invoices/nfcom/full/sync`.


        Integrações novas devem usar `POST /v2/invoices/nfcom/full`.


        ### Alíquotas


        - `icms_aliquot`, `pis_pasep_aliquot` e `cofins_aliquot`: `0` ou ausente usa a configuração da empresa
          (PIS/COFINS com CST 01/02). Diferente do `/full` e do `/full/sync`, que devolvem 400 para ICMS 0 com
          CST 00, o legado aceita `icms_aliquot: 0` com CST 00 e emite com a alíquota de ICMS da configuração.

        ### Validações antes de transmitir (400)


        - `client.address` (com `state`) é obrigatório.

        - `classification_code` precisa existir na tabela de classificação da NFCom (tabela cClass do portal SVRS, 85
        códigos); códigos
          legados do Convênio 115 são convertidos antes da validação.
        - `discount` não pode ser maior que `unitary_value × quantity`.


        ### Outras despesas


        O campo `other_values` do item é aceito por compatibilidade, mas **não é usado**: a NFCom do legado sai

        sempre com vOutro 0. Para cobrar outras despesas (vOutro), use `other_expenses` em `POST
        /v2/invoices/nfcom/full`.

        - FUST e FUNTTEL não vêm no item: usam a configuração da empresa (ou as tags de `observation`).

        - `aliquota_zero` funciona como na API v2: `true` zera PIS, COFINS, FUST e FUNTTEL do item; a lista zera
          só os tributos listados. O pedido também prevalece sobre as tags e a configuração. Tributo pedido com
          alíquota maior que 0 no mesmo item (`pis_pasep_aliquot`, `cofins_aliquot`) retorna 400. `icms` não é aceito.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - issue_date
                - service_date
                - cfop
                - subscriber_type
                - type_of_use
                - client
                - items
              properties:
                integration_id:
                  type: string
                  description: Identificador da integração. Vira o `external_reference` da NFCom.
                model:
                  type: number
                  description: Modelo legado (21 ou 22).
                series:
                  type: string
                  description: Série (só números, até 999).
                issue_date:
                  type: string
                  format: date
                service_date:
                  type: string
                  format: date
                end_service_date:
                  type: string
                  format: date
                  nullable: true
                cfop:
                  type: string
                subscriber_type:
                  type: string
                type_of_use:
                  type: string
                observation:
                  type: string
                  description: Observações. Aceita as tags flexíveis de tributação.
                service_discrimination:
                  type: string
                  maxLength: 1500
                generate_pdf:
                  type: boolean
                  default: false
                tax_exempted:
                  type: boolean
                  default: false
                client:
                  type: object
                  description: Destinatário (nome, documento, IE, contatos e endereço).
                responsible:
                  type: object
                  description: Responsável (opcional).
                items:
                  type: array
                  items:
                    type: object
                    required:
                      - description
                      - quantity
                      - unitary_value
                      - classification_code
                    properties:
                      description:
                        type: string
                        maxLength: 120
                      quantity:
                        type: number
                      unitary_value:
                        type: number
                        minimum: 0
                      classification_code:
                        type: string
                      discount:
                        type: number
                        description: Desconto do item. Maior que `unitary_value × quantity` retorna 400.
                      other_values:
                        type: number
                        description: Aceito por compatibilidade e ignorado (vOutro sai 0 no legado).
                      icms_aliquot:
                        type: number
                        description: Alíquota do ICMS. `0` ou ausente usa a configuração da empresa; o ICMS 0 segue a regra do CST.
                      pis_pasep_aliquot:
                        type: number
                        description: Alíquota do PIS. `0` ou ausente usa a configuração da empresa. Para emitir 0, envie `aliquota_zero`.
                      cofins_aliquot:
                        type: number
                        description: Alíquota da COFINS. `0` ou ausente usa a configuração da empresa. Para emitir 0, envie `aliquota_zero`.
                      tax_exempted:
                        type: boolean
                        default: false
                      aliquota_zero: *a6
            example:
              integration_id: pedido-123
              model: 21
              issue_date: 2026-10-26
              service_date: 2026-10-26
              cfop: "5307"
              subscriber_type: "3"
              type_of_use: "1"
              client:
                name: Cliente Exemplo
                document: 00.000.000/0001-91
                contacts:
                  phone: "95999999999"
                address:
                  street: Rua Exemplo
                  number: "100"
                  district: Centro
                  city: Caroebe
                  state: RR
                  zip_code: 69378-000
              items:
                - description: Internet 100 Mbps
                  quantity: 1
                  unitary_value: 99.9
                  classification_code: "0100101"
                  pis_pasep_aliquot: 0
                  cofins_aliquot: 0
                  aliquota_zero:
                    - pis
                    - cofins
      responses:
        "200":
          description: NFCom criada (a transmissão pode ter sido autorizada ou ter falhado)
          content:
            application/json:
              schema: *a7
        "400":
          description: Dados inválidos (inclui conflito de `aliquota_zero`, `icms` na lista, tomador sem endereço, cClass fora da
            tabela e desconto maior que o item)
          content:
            application/json:
              schema: *a1
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a4
        "500":
          description: Erro interno
          content:
            application/json:
              schema: *a5
  /v2/invoices/nfcom/full/{id}:
    put:
      tags:
        - NFCom
      summary: Atualizar NFCom Completa
      description: |
        Atualiza completamente uma NFCom existente (substitui todos os dados do body).

        O contrato do body é o mesmo do `POST /v2/invoices/nfcom/full`
        (`abroad`, `usage_type`, `client.address.country_*`, itens, faturamento, etc.).
        A **série** continua vindo das **Configurações** da empresa (não é enviada no payload).

        ⚠️ **ATENÇÃO**:
        - Esta operação substitui TODOS os dados da NFCom
        - Para atualização parcial, use `PATCH /v2/invoices/nfcom/full/{id}`
        - Só permite atualização em status `DRAFT` ou `SUBMISSION_ERROR`
        - Com `issue_finality = 3`, informe `substitute_reason` e `original_access_key`
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: ID único da NFCom a ser atualizada
          example: 123e4567-e89b-12d3-a456-426614174000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - model
                - issue_date
                - issue_finality
                - client
                - items
              description: |
                Atualização completa: o body segue as mesmas regras do `POST /v2/invoices/nfcom/full`.
                Só é permitido em status `DRAFT` ou `SUBMISSION_ERROR`.
              properties:
                external_reference: *a8
                notification_url:
                  type: string
                  format: uri
                  nullable: true
                  example: https://seu-sistema.com/webhook/nfcom-notifications
                  description: |
                    URL de webhook para esta NFCom.
                    - Valor informado: define/atualiza a URL específica
                    - `null` ou `""`: remove o webhook específico (usa o do sistema, se houver)
                    - Omitido: mantém a URL já gravada na NFCom
                model: *a9
                issue_date: *a10
                issue_finality: *a11
                substitute_reason: *a12
                prepaid_service_indicator: *a13
                network_media_session_indicator: *a14
                reference_model: *a15
                reference_month_year: *a16
                reference_series: *a17
                reference_number: *a18
                hash_convention_115: *a19
                original_access_key: *a20
                observation: *a21
                service_description: *a22
                client: *a23
                items: *a24
                billing_info: *a25
                autoTransmit: *a26
                emailNotificationAttachments: *a27
            examples:
              example_nfcom_requered:
                summary: NFCom - Dados mínimos requeridos
                description: Exemplo de criação de NFCom com os dados mínimos requeridos
                value:
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    indicator_ie: 9
                    subscriber_type: 1
                    address:
                      number: "935"
                      zip_code: 09015-660
                  items:
                    - code: INET100
                      description: Internet Banda Larga 100MB
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 89.9
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-08-26
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
              exemplo_nfcom_normal:
                summary: NFCom com faturamento normal
                description: Exemplo de criação de NFCom com faturamento normal, incluindo todos os campos obrigatórios e opcionais
                  principais
                value:
                  external_reference: REF-EXTERNA-2025-001
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: Serviços de telecomunicações prestados no período de Agosto/2025
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 4
                    contract_number: CONT-2025-001
                    contract_start_date: 2025-01-01
                    main_terminal_number: "11999887766"
                    terminal_uf_code: SP
                    address:
                      street: Travessa Mariana Lotto
                      number: "720"
                      complement: Apto 45
                      neighborhood: Centro
                      city: São Bernardo do Campo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "09710070"
                    contacts:
                      email: joao.santos@email.com
                      phone: "11999887766"
                  items:
                    - code: INET100
                      description: Internet Banda Larga 100MB
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 89.9
                      discount_value: 5
                      other_expenses: 2
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-08-26
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
                    barcode: "34195175152345678712834123456005110185000002603"
                    pix_url: https://pix.banco.com.br/qr/v2/cobv/4f9e...
                    bank_code: "341"
                    branch_code: "1234"
                    bank_slip: "01234567890123456"
                    correspondence_address_type: client
              exemplo_nfcom_substituicao:
                summary: NFCom de substituição
                description: Exemplo de NFCom de substituição com referência à nota original
                value:
                  external_reference: REF-SUBSTITUICAO-2025-002
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 3
                  substitute_reason: 1
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  reference_model: 62
                  reference_month_year: "202508"
                  reference_series: "1"
                  reference_number: 123
                  original_access_key: "35240812345678000123620010000001231234567890"
                  observation: NFCom de substituição - correção de dados
                  client:
                    name: Kauê Henry Ferreira
                    document: "88061827816"
                    ie: "123456789012"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 1
                    contract_number: CONT-PJ-2025-002
                    contract_start_date: 2025-06-01
                    main_terminal_number: "11888776655"
                    terminal_uf_code: SP
                    address:
                      street: Travessa Mariana Lotto
                      number: "720"
                      complement: Apto 45
                      neighborhood: Centro
                      city: São Bernardo do Campo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "09710070"
                    contacts:
                      email: contato@mariaempresa.com.br
                      phone: "1133334444"
                  items:
                    - code: INET500
                      description: Internet Banda Larga 500MB Empresarial
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 299.9
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      icms_bc_reduction: 0
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
                    competence: "202508"
                    due_date: 2025-09-25
                    usage_period_start: 2025-08-01
                    usage_period_end: 2025-08-31
                    pix_url: https://pix.banco.com.br/qr/v2/cobv/5g8f...
                    bank_code: "237"
                    correspondence_address_type: custom
                    correspondence_street: Rua da Correspondência
                    correspondence_number: "456"
                    correspondence_neighborhood: Jardim América
                    correspondence_city: São Paulo
                    correspondence_uf: SP
                    correspondence_zip_code: "01234567"
                    correspondence_email: financeiro@mariaempresa.com.br
                    correspondence_phone: "1144445555"
              exemplo_nfcom_centralizado:
                summary: NFCom com faturamento centralizado
                description: Exemplo de NFCom com faturamento centralizado por empresa matriz
                value:
                  external_reference: REF-2025-003
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: Faturamento centralizado - Filial Norte
                  client:
                    name: Empresa Filial Norte Ltda
                    document: "98765432000188"
                    ie: "987654321098"
                    indicator_ie: 1
                    subscriber_type: 2
                    usage_type: 3
                    contract_number: CONT-2025-003
                    contract_start_date: 2025-05-15
                    main_terminal_number: "11777665544"
                    terminal_uf_code: SP
                    address:
                      street: Rua do Comércio
                      number: "789"
                      neighborhood: Vila Industrial
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "04567890"
                    contacts:
                      email: filial.norte@empresa.com.br
                      phone: "1155556666"
                  items:
                    - code: VOIP200
                      description: VOIP Empresarial 200 ramais
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 1500
                      discount_value: 100
                      other_expenses: 50
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 1
                    centralized_company_cnpj: "12345678000100"
                    centralized_company_uf: SP
                    correspondence_address_type: none
              exemplo_nfcom_cofaturamento:
                summary: NFCom com cofaturamento
                description: Exemplo de NFCom com cofaturamento referenciando outra NFCom
                value:
                  external_reference: REF-COFAT-2025-004
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 0
                  network_media_session_indicator: 0
                  observation: NFCom de cofaturamento
                  client:
                    name: Empresa Parceira Ltda
                    document: "11223344000155"
                    ie: "112233445566"
                    indicator_ie: 1
                    subscriber_type: 2
                    usage_type: 4
                    contract_number: CONT-COFAT-2025-004
                    contract_start_date: 2025-07-01
                    main_terminal_number: "11666555444"
                    terminal_uf_code: SP
                    address:
                      street: Av. das Nações
                      number: "1500"
                      complement: Torre A
                      neighborhood: Brooklin
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "04578000"
                    contacts:
                      email: parceria@empresa.com.br
                      phone: "1199998888"
                  items:
                    - code: INFRA100
                      description: Compartilhamento de Infraestrutura
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 800
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 2
                    nfcom_local_key: "35240812345678000123620010000001001234567890"
                    correspondence_address_type: none
              exemplo_nfcom_prepago:
                summary: NFCom de serviço pré-pago
                description: Exemplo de NFCom para serviços pré-pagos (não requer informações de faturamento)
                value:
                  external_reference: REF-PREPAGO-2025-005
                  model: 62
                  issue_date: 2025-08-26
                  issue_finality: 0
                  prepaid_service_indicator: 1
                  network_media_session_indicator: 0
                  observation: Recarga de créditos - serviço pré-pago
                  client:
                    name: Carlos Alberto Pereira
                    document: "98765432100"
                    indicator_ie: 9
                    subscriber_type: 1
                    usage_type: 5
                    contract_number: PREP-2025-005
                    contract_start_date: 2025-08-23
                    main_terminal_number: "11987654321"
                    terminal_uf_code: SP
                    address:
                      street: Rua dos Trabalhadores
                      number: "456"
                      neighborhood: Vila Nova
                      city: São Paulo
                      city_code: "3550308"
                      uf: SP
                      zip_code: "03456789"
                    contacts:
                      email: carlos.pereira@email.com
                      phone: "11987654321"
                  items:
                    - code: CRED30
                      description: Créditos R$ 30,00
                      classification_code: "0400401"
                      cfop: "5301"
                      unity: 1
                      quantity: 1
                      unit_value: 30
                      discount_value: 0
                      other_expenses: 0
                      icms_cst: "00"
                      icms_rate: 18
                      pis_cst: "01"
                      pis_rate: 1.65
                      cofins_cst: "01"
                      cofins_rate: 7.6
                      fust_rate: 1
                      funttel_rate: 0.5
                  billing_info:
                    billing_type: 0
      responses:
        "200":
          description: NFCom atualizada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: NFCom atualizada com sucesso
                  data:
                    type: object
                    properties:
                      nfcom_id:
                        type: string
                        format: uuid
                        description: ID único da NFCom atualizada
                        example: 123e4567-e89b-12d3-a456-426614174000
                      series:
                        type: string
                        description: Série da NFCom
                        example: "1"
                      issue_date:
                        type: string
                        format: date-time
                        description: Data de emissão
                        example: 2025-09-01T10:30:00.000Z
                      status:
                        type: string
                        description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                          retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a
                          SEFAZ). Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais;
                          PENDING_SUBMISSION na fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada
                          ou com erro no envio; PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED
                          cancelada; CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED
                          substituída por outra NFCom."
                        enum:
                          - DRAFT
                          - PENDING_SUBMISSION
                          - SUBMITTING
                          - SUBMITTED
                          - VALIDATED
                          - PENDING_CANCELLATION
                          - CANCELLING
                          - CANCELLED
                          - REPLACED
                          - SUBMISSION_ERROR
                          - CANCELLATION_ERROR
                        example: PENDING_SUBMISSION
                      total_value:
                        type: number
                        format: decimal
                        description: Valor total da NFCom
                        example: 150.75
                      environment:
                        type: string
                        description: Ambiente de emissão (produção ou homologação)
                        enum:
                          - producao
                          - homologacao
                        example: homologacao
        "400":
          description: Dados inválidos
          content:
            application/json:
              schema: *a1
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a4
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: &a28
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: NFCom não encontrada
        "422":
          description: Erro de validação
          content:
            application/json:
              schema: *a1
        "500":
          description: Erro interno do servidor
          content:
            application/json:
              schema: *a5
    patch:
      tags:
        - NFCom
      summary: Atualizar NFCom Parcialmente
      description: |
        Atualiza parcialmente uma NFCom existente (apenas os campos informados).

        ⚠️ **ATENÇÃO**:
        - Atualiza apenas os campos informados no body
        - Só permite atualização de NFCom em status `DRAFT` ou `SUBMISSION_ERROR`
        - Pelo menos um campo deve ser informado
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: ID único da NFCom a ser atualizada
          example: 123e4567-e89b-12d3-a456-426614174000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              minProperties: 1
              description: |
                **Atualização Parcial**: Todos os campos são opcionais.
                Pelo menos um campo deve ser informado.
                Apenas os campos enviados serão atualizados.
              properties:
                external_reference:
                  type: string
                  maxLength: 255
                  example: REF-EXTERNA-2024-001
                  description: Referência externa para integração
                notification_url:
                  type: string
                  format: uri
                  nullable: true
                  example: https://seu-sistema.com/webhook/nfcom-notifications
                  description: |
                    **URL de webhook para notificações desta NFCom**
                    - Se informado: Nova URL específica para esta NFCom
                    - Se `null`: Remove webhook específico, usa URL do sistema
                    - Se omitido: Mantém URL atual
                model:
                  type: integer
                  enum:
                    - 62
                  example: 62
                  description: Modelo da nota fiscal (sempre 62 para NFCom)
                issue_date:
                  type: string
                  format: date-time
                  example: 2024-08-21T10:30:00.000Z
                  description: |
                    Data/hora de emissão da nota fiscal

                    **⚠️ Validações:**
                    - Não pode ser maior que a data atual
                    - Não pode ser anterior a 5 dias da data atual
                issue_finality:
                  type: integer
                  enum:
                    - 0
                    - 3
                    - 4
                  example: 0
                  description: |
                    Finalidade da emissão:
                    - 0: Normal
                    - 3: Substituição
                    - 4: Ajuste
                substitute_reason:
                  type: integer
                  example: 1
                  description: Motivo de substituição (obrigatório se issue_finality = 3)
                prepaid_service_indicator:
                  type: integer
                  enum:
                    - 0
                    - 1
                  example: 0
                  description: |
                    Indicador de serviço pré-pago:
                    - 0: Não
                    - 1: Sim
                network_media_session_indicator:
                  type: integer
                  enum:
                    - 0
                    - 1
                  example: 0
                  description: |
                    Indicador de sessão de mídia em rede:
                    - 0: Não
                    - 1: Sim
                reference_model:
                  type: integer
                  example: 21
                  description: Modelo de referência
                reference_month_year:
                  type: string
                  example: 08/2024
                  description: Mês/ano de referência (formato livre no PATCH; create full usa regras por modelo)
                reference_series:
                  type: string
                  example: "001"
                  description: Série de referência
                reference_number:
                  type: integer
                  example: 123
                  description: Número de referência
                hash_convention_115:
                  type: string
                  example: hash123
                  description: Hash da convenção 115
                original_access_key:
                  type: string
                  example: "35240814200166000187620010000001231234567890"
                  description: Chave de acesso original
                observation:
                  type: string
                  maxLength: 2000
                  example: Observações adicionais sobre a NFCom
                  description: Observações da NFCom
                service_description:
                  type: string
                  example: Serviços de telecomunicação
                  description: Descrição do serviço
                client:
                  type: object
                  description: |
                    Dados do cliente (opcional no PATCH).
                    Se informado, deve conter pelo menos name e document.
                  properties:
                    name:
                      type: string
                      minLength: 1
                      maxLength: 60
                      example: João da Silva
                      description: Nome/Razão social do cliente (máx. 60)
                    document:
                      type: string
                      maxLength: 20
                      example: "12345678901"
                      description: CPF/CNPJ (BR) ou documento estrangeiro (2–20 chars ASCII)
                    ie:
                      type: string
                      example: "123456789"
                      description: Inscrição Estadual
                    im:
                      type: string
                      example: "123456789"
                      description: Inscrição Municipal
                    abroad:
                      type: boolean
                      default: false
                      description: Cliente estrangeiro
                    indicator_ie:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 9
                      example: 1
                      description: |
                        Indicador de IE:
                        - 1: Contribuinte
                        - 2: Isento
                        - 9: Não Contribuinte (obrigatório para estrangeiro/CPF)
                    subscriber_type:
                      type: integer
                      minimum: 1
                      maximum: 99
                      example: 1
                      description: Tipo de assinante (1-99)
                    usage_type:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 3
                        - 4
                        - 5
                        - 6
                        - 7
                      example: 4
                      description: |
                        Tipo de utilização:
                        - 1 Telefonia, 2 Comunicação de dados, 3 TV, 4 Internet, 5 Multimídia, 6 Outros, 7 Vários
                    subscriber_code:
                      type: string
                      maxLength: 15
                      description: Código do assinante
                    service_type:
                      type: number
                      description: Campo legado (opcional no PATCH)
                    contract_number:
                      type: string
                      maxLength: 20
                      example: CONT-001
                      description: Número do contrato
                    contract_start_date:
                      type: string
                      format: date-time
                      example: 2024-01-01T00:00:00.000Z
                      description: Data de início do contrato
                    contract_end_date:
                      type: string
                      format: date-time
                      example: 2024-12-31T23:59:59.000Z
                      description: Data de fim do contrato (não anterior ao início)
                    main_terminal_number:
                      type: string
                      example: "11987654321"
                      description: Número do terminal principal
                    terminal_uf_code:
                      type: string
                      maxLength: 2
                      example: SP
                      description: UF do terminal
                    address:
                      type: object
                      description: Endereço (todos os campos opcionais no PATCH)
                      properties:
                        street:
                          type: string
                          maxLength: 255
                          example: Rua das Flores
                        number:
                          type: string
                          maxLength: 60
                          example: "123"
                        complement:
                          type: string
                          maxLength: 255
                          example: Apto 45
                        neighborhood:
                          type: string
                          maxLength: 255
                          example: Centro
                        city:
                          type: string
                          maxLength: 255
                          example: São Paulo
                        city_code:
                          type: string
                          minLength: 7
                          maxLength: 7
                          example: "3550308"
                          description: Código IBGE (7 dígitos)
                        uf:
                          type: string
                          minLength: 2
                          maxLength: 2
                          example: SP
                        zip_code:
                          type: string
                          example: "01234567"
                          description: CEP com ou sem formatação (8 dígitos)
                        country:
                          type: string
                          enum:
                            - BR
                          example: BR
                        country_code:
                          type: number
                          nullable: true
                        country_name:
                          type: string
                          nullable: true
                    phones:
                      type: array
                      description: Telefones do cliente (substitui lista se enviado)
                      items:
                        type: object
                        required:
                          - type
                          - number
                        properties:
                          type:
                            type: string
                            enum:
                              - "1"
                              - "2"
                              - "3"
                            description: 1=Residencial, 2=Comercial, 3=Celular
                          number:
                            type: string
                            example: "11987654321"
                            description: 10 a 12 dígitos (com DDD)
                services:
                  type: array
                  description: |
                    Se informado, **substitui** todos os serviços da NFCom.
                    Shape aceito pelo PATCH (não é o mesmo de `items` do POST/PUT full).
                  items:
                    type: object
                    required:
                      - service_classification
                      - item_list_service_provision
                      - service_code
                      - service_description
                      - unit
                      - quantity
                      - unit_price
                      - total_price
                      - taxation
                    properties:
                      item_number:
                        type: integer
                        minimum: 1
                        example: 1
                      service_classification:
                        type: integer
                        minimum: 1
                        maximum: 9999999
                        example: 401
                        description: >
                          Código legado (até 4 dígitos, convertido pela tabela de classificação) ou cClass da NFCom (7
                          dígitos).

                          Códigos sem correspondência, fora do formato de 7 dígitos ou ausentes da tabela de
                          classificação da NFCom retornam 422.
                      item_list_service_provision:
                        type: integer
                        minimum: 1
                        maximum: 999
                        example: 1
                      service_code:
                        type: string
                        maxLength: 20
                        example: TEL001
                      service_description:
                        type: string
                        minLength: 1
                        maxLength: 2000
                        example: Serviço de telefonia móvel
                      unit:
                        type: string
                        minLength: 1
                        maxLength: 6
                        example: UN
                      quantity:
                        type: number
                        minimum: 0.0001
                        example: 1
                      unit_price:
                        type: number
                        minimum: 0
                        example: 50.75
                      total_price:
                        type: number
                        minimum: 0
                        example: 50.75
                      discount_amount:
                        type: number
                        minimum: 0
                        description: Desconto do item (vDesc). Não pode ser maior que unit_price × quantity + other_expenses_amount (400).
                        example: 5
                      other_expenses_amount:
                        type: number
                        minimum: 0
                        description: Outras despesas acessórias do item (vOutro). Entram no vProd do item (vItem × qFaturada − vDesc + vOutro,
                          MOC G86), no vOutro do total, no vNF e nas bases dos tributos.
                        example: 0
                      cfop:
                        type: string
                        nullable: true
                        example: "5307"
                      taxation:
                        type: object
                        required:
                          - icms_situation
                        properties:
                          icms_situation:
                            type: integer
                            minimum: 0
                            maximum: 999
                            example: 20
                          icms_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                            example: 18
                          icms_interstate_rate:
                            type: number
                            nullable: true
                            minimum: 0
                            maximum: 100
                          icms_base:
                            type: number
                            minimum: 0
                          icms_amount:
                            type: number
                            minimum: 0
                          fcp_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                          fcp_amount:
                            type: number
                            minimum: 0
                          pis_cst:
                            type: string
                            enum:
                              - "01"
                              - "02"
                              - "06"
                              - "07"
                              - "08"
                              - "09"
                              - "49"
                            example: "01"
                            description: CST do PIS. Se omitido, usa o CST do serviço cadastrado com o mesmo service_code e, se o serviço não tiver,
                              o da configuração da empresa.
                          cofins_cst:
                            type: string
                            enum:
                              - "01"
                              - "02"
                              - "06"
                              - "07"
                              - "08"
                              - "09"
                              - "49"
                            example: "01"
                            description: CST da COFINS. Se omitido, usa o CST do serviço cadastrado com o mesmo service_code e, se o serviço não
                              tiver, o da configuração da empresa.
                          pis_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                            example: 0.65
                            description: Alíquota do PIS (%). 0 ou omitido usa a alíquota do serviço cadastrado quando o CST vem dele e, senão, a da
                              configuração da empresa. Para emitir 0, envie `aliquota_zero`.
                          cofins_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                            example: 3
                            description: Alíquota da COFINS (%). 0 ou omitido usa a alíquota do serviço cadastrado quando o CST vem dele e, senão, a
                              da configuração da empresa. Para emitir 0, envie `aliquota_zero`.
                          fust_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                            example: 1
                            description: Alíquota do FUST (%). 0 é gravado como 0; omitido usa a alíquota da configuração da empresa.
                          funttel_rate:
                            type: number
                            minimum: 0
                            maximum: 100
                            example: 0.5
                            description: Alíquota do FUNTTEL (%). 0 é gravado como 0; omitido usa a alíquota da configuração da empresa.
                          aliquota_zero: *a6
                billing_info: *a25
            examples:
              clientUpdate:
                summary: Atualizar data de emissão e dados do cliente
                value:
                  issue_date: 2025-08-24
                  client:
                    name: Kauê Henry Ferreira
                    document: 049.920.438-79
                    address:
                      number: "8588"
                      zip_code: 79814-335
              multipleFields:
                summary: Atualização de múltiplos campos
                value:
                  notification_url: https://sistema.com/webhook
                  issue_date: 2025-08-24
                  observation: Observação atualizada após correção
                  client:
                    name: Kauê Henry Ferreira
                    document: 049.920.438-79
                    email: kaue.henry@email.com
                    address:
                      number: "8588"
                      zip_code: 79814-335
              itemsOnly:
                summary: Atualizar apenas lista de itens
                value:
                  items:
                    - description: Serviço Corrigido
                      quantity: 1
                      unit_price: 99.99
                      cfop: "5307"
                      item_list_service_code: "09.02"
                    - description: Novo Serviço Adicional
                      quantity: 1
                      unit_price: 49.9
                      cfop: "5307"
                      item_list_service_code: "09.03"
      responses:
        "200":
          description: NFCom atualizada parcialmente com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: NFCom atualizada parcialmente com sucesso
                  data:
                    type: object
                    properties:
                      nfcom_id:
                        type: string
                        format: uuid
                        description: ID único da NFCom atualizada
                        example: 123e4567-e89b-12d3-a456-426614174000
                      series:
                        type: string
                        description: Série da NFCom
                        example: "1"
                      issue_date:
                        type: string
                        format: date-time
                        description: Data de emissão
                        example: 2025-09-01T10:30:00.000Z
                      status:
                        type: string
                        description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                          retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a
                          SEFAZ). Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais;
                          PENDING_SUBMISSION na fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada
                          ou com erro no envio; PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED
                          cancelada; CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED
                          substituída por outra NFCom."
                        enum:
                          - DRAFT
                          - PENDING_SUBMISSION
                          - SUBMITTING
                          - SUBMITTED
                          - VALIDATED
                          - PENDING_CANCELLATION
                          - CANCELLING
                          - CANCELLED
                          - REPLACED
                          - SUBMISSION_ERROR
                          - CANCELLATION_ERROR
                        example: PENDING_SUBMISSION
                      total_value:
                        type: number
                        format: decimal
                        description: Valor total da NFCom
                        example: 150.75
        "400":
          description: Dados inválidos
          content:
            application/json:
              schema: *a1
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a4
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a28
        "422":
          description: Erro de validação
          content:
            application/json:
              schema: *a1
        "500":
          description: Erro interno do servidor
          content:
            application/json:
              schema: *a5
  /v2/invoices/nfse/full:
    post:
      tags:
        - NFS-e
      summary: Criar NFS-e completa
      description: >
        **Endpoint de integração.** Cria uma NFS-e com os dados enviados no payload.

        O sistema localiza o tomador pelo CPF/CNPJ e o serviço pelo `codigo_servico` (código interno).

        O campo `items[].codigo_interno` é aceito como alias de `codigo_servico`.

        Se não existirem, cadastra. Se existirem, reutiliza **sem alterar o cadastro**:

        a nota sai com os dados do payload (nome/endereço do tomador, descrição e campos fiscais do item).


        - **Serviço existente:** o valor sugerido e os campos já preenchidos nunca mudam. Só campos fiscais
          ou a descrição que estiverem **vazios** no cadastro são completados com o que veio no item.
        - **Tomador existente:** o cadastro só é atualizado (nome, IM e endereço) se você enviar
          `client.update_registration: true`.

        Por padrão a nota é **enfileirada** para transmissão (SEFIN nacional ou ADN municipal).

        Envie `autoTransmit: false` para gravar somente o rascunho.


        A série e o ambiente saem das configurações de NFS-e da empresa. O regime tributário (Simples Nacional,

        apuração e regime especial) é o de **Minha empresa** (a API ainda aceita os mesmos campos nas

        configurações de NFS-e como alias).

        A resposta volta com `id` e o status inicial (`pending` ou `draft`).

        A autorização chega depois, pela fila.


        ### Payload mínimo

        Com o tomador já cadastrado e um serviço padrão na empresa, basta:


        ```json

        { "external_id": "PED-2026-0001", "client": { "document": "12.345.678/0001-90" }, "items": [{ "valor": 109.00 }]
        }

        ```


        - `competencia` ausente → mês atual (horário de Brasília).

        - `client.name` ausente → usa o nome do cadastro do tomador (obrigatório só para cadastrar um novo).

        - `items[].codigo_servico` (ou o alias `codigo_interno`) ausente → usa o **serviço padrão**
          (Configurações → Integrações → Serviço padrão da API) ou, sem padrão, o único serviço ativo da
          empresa. Com mais de um serviço e sem padrão, a API responde `422` com o campo `items.0.codigo_servico`.
        - A busca do serviço usa o código interno (`code`). Se não achar, tenta o valor antigo gravado em
          `c_int_contrib` (notas que já usavam esse campo continuam encontrando o serviço).

        ### Obrigatório para cadastrar um tomador novo

        - `client.document`, `client.name`

        - `client.address.zip_code` (8 dígitos) quando o endereço for exigido (veja abaixo)


        Cidade, UF e IBGE são descobertos pelo CEP (logradouro e bairro também, se vierem vazios).

        Se o CEP não for encontrado, envie `client.address.city` + `client.address.state`

        ou `client.address.city_code` (IBGE, 7 dígitos).


        ### Endereço do tomador

        O endereço é obrigatório (padrão nacional, Anexo I v1.01) quando:

        - o tomador tem **CNPJ** (E0235);

        - o ISS é **retido pelo tomador** (`tp_ret_issqn = 2`, E0237);

        - o serviço tem ISS devido no **local do tomador** (`c_trib_nac` 170501, E0234);

        - o `c_ind_op` é 030102, 030103, 050102, 050103, 100101, 100102, 100201, 100301, 100302,
          100401, 100501, 100502 ou 100601 (E0234);
        - o tomador é **estrangeiro com NIF** (ou motivo de não ter NIF) e o emitente tem CNPJ: exige o
          endereço no exterior (E0242).

        Fora desses casos, tomador **CPF** pode ir sem endereço: a DPS sai sem o grupo `end`

        (nenhum endereço fictício é enviado). Tomador já cadastrado sem o endereço exigido → `422`,

        sem transmitir. Quando houver endereço, o CEP precisa ser da cidade informada (E0240);

        se a consulta de CEP estiver indisponível, a conferência é pulada.


        ### Obrigatório para cadastrar um serviço novo

        - `codigo_servico`, `valor`

        - `c_trib_nac` (6), `c_nbs` (9), `c_ind_op` (6), `ibs_cst` (3), `c_class_trib` (6)


        ### Tributação padrão

        Campo fiscal não enviado vem, nesta ordem: do item → do cadastro do serviço → da

        **tributação padrão** definida em Configuração → NFS-e (enquadramento fiscal, ISS,

        PIS/COFINS e IBS/CBS). Com o padrão configurado, os códigos acima podem ser omitidos.

        Tributação municipal e NBS padrão só valem para o mesmo `c_trib_nac` do padrão;

        alíquotas PIS/COFINS padrão só valem junto do CST PIS/COFINS padrão.


        Obra, evento e intermediário são exigidos quando a tributação nacional pede (regras abaixo).


        ### Indicador da operação (`c_ind_op`)

        O cIndOp da nota vem, nesta ordem: do item (`items[].c_ind_op`) → do cadastro do serviço → da

        tributação padrão (Configuração → NFS-e). **Não há valor padrão no sistema**: sem nenhum dos três,

        a nota não é transmitida e a API responde `422` com `error.code = CINDOP_REQUIRED`

        (o campo vem em `error.fields`). No lote, só a nota sem cIndOp volta com esse erro; as outras seguem.

        No painel, o campo fica na aba Serviço (classificação); o cadastro do serviço guarda o padrão.

        Exceção: com CST do IBS/CBS que não gera tributação (400, 410, 620, 800, 810, 811, 820) o cIndOp

        é opcional e não vai na DPS do leiaute NT 009 (a SEFIN recusa com E0859).


        ### CST e classificação do IBS/CBS (`ibs_cst`, `c_class_trib`)

        Os campos são `items[].ibs_cst` e `items[].c_class_trib` (ou `servico.ibs_cst` e `servico.c_class_trib`).

        Não existe campo `cst`. Informando só `c_class_trib`, o CST sai dos 3 primeiros dígitos (410027 → 410).

        CST e classificação de grupos diferentes: `422` com `error.code = IBSCBS_CST_CLASSTRIB`.


        ### Serviço 99.01.01 (não incidência)

        A DPS sempre leva o grupo IBS/CBS (obrigatório desde a competência 10/2026) e, com ele, a SEFIN exige

        o NBS (E0322). Sem `c_nbs` no item, na nota ou no cadastro do serviço, a API responde `422` com

        `error.code = NBS_REQUIRED` antes de transmitir. O NBS padrão da empresa não é usado para este código.


        ### Imóvel (`ibscbs.imovel`) — Anexo I RN v1.01 E0931/E0932

        O grupo `imovel` **não é enviado** quando `c_trib_nac` é de construção civil

        (07.02.01, 07.02.02, 07.04.01, 07.05.01, 07.05.02, 07.06.01, 07.06.02, 07.07.01, 07.08.01,

        07.17.01, 07.19.01). Nos demais códigos, é **obrigatório** se `c_ind_op` for 020101, 020201 ou

        020301; com qualquer outro indicador o grupo é omitido. CIB (E0933) e endereço no exterior

        (E0934/E0935) continuam validados quando o bloco vai na DPS.


        ### Obra (`obra`) — Anexo I RN v1.01 E0370/E0372

        O grupo `obra` é **obrigatório** para 07.02.01, 07.02.02, 07.04.01, 07.05.01, 07.05.02,

        07.06.01, 07.06.02, 07.07.01, 07.08.01, 07.17.01, 07.19.01, 14.14.03 e 14.14.04; **opcional**

        em 99.01.01; nos demais códigos o grupo é omitido.


        ### Evitar nota duplicada (`external_id`)

        Envie `external_id` (ou o cabeçalho `Idempotency-Key`) com o identificador da cobrança no seu

        sistema. Se a requisição der timeout e você reenviar, a API devolve a NFS-e já criada

        (HTTP 200, `duplicate: true`, mesma estrutura da criação) em vez de emitir outra. Para consultar

        depois: `GET /v2/invoices/nfse?external_id=...`.


        - O `external_id` é único **por empresa e ambiente**: o mesmo valor pode ser usado uma vez em
          homologação e outra em produção.
        - Sem `external_id` (ausente ou `""`) e sem `Idempotency-Key`, a nota é criada e a resposta traz
          `warning` avisando que um reenvio emitirá outra nota.
        - Cabeçalho `Idempotency-Key` enviado vazio ou só com espaços → `400` (`code: EXTERNAL_ID_BLANK`).

        - Reenvio com o **mesmo conteúdo** → `200 duplicate: true`. A comparação ignora ordem dos campos,
          espaços nas pontas, máscara do CPF/CNPJ, do CEP e do telefone, maiúsculas/espaços do e-mail,
          `autoTransmit` e `client.update_registration`.
        - Depois de corrigir a nota com `PUT /v2/invoices/nfse/full/{id}`, a comparação continua sendo com o
          **POST original**: repetir aquele POST devolve `200 duplicate: true` com a nota já corrigida (não 409).
          Se o PUT trocar o `external_id`, a referência passa a ser o conteúdo do PUT.
        - Reenvio com **conteúdo diferente** (outro valor, tomador, serviço, competência…) → `409` com
          `error.code = EXTERNAL_ID_CONFLICT` e `error.details.id` da nota existente. Use um `external_id` novo.
        - Reenvio de uma nota que está em **rascunho ou com erro de envio** não transmite nada, mesmo
          com `autoTransmit: true`. A resposta traz `next_action` apontando para
          `POST /v2/invoices/nfse/{id}/retransmit` (transmitir como está) — ou use
          `PUT /v2/invoices/nfse/full/{id}` para corrigir antes.
        - Se a prefeitura respondeu E0014 (DPS já recebida) e a consulta dessa DPS ainda não confirmou
          o resultado, o `retransmit` responde `409` com `error.code = NFSE_RETRANSMIT_PENDING_CONSULT`
          e não gera um novo número de DPS (evita nota em duplicidade). Isso vale também quando a DPS é
          encontrada mas o XML da nota não pode ser lido (vem vazio, com erro ou incompleto): a consulta
          responde `502 NFSE_CONSULTA_INCONCLUSIVA`. Consulte a nota de novo
          (`POST /v2/invoices/nfse/{id}/refresh`); um número novo só é usado quando o XML confirma que a
          DPS é de outra nota (tomador, valor ou competência diferentes).
        - `external_id` só com espaços → `400` (string vazia continua aceita e desliga a idempotência).

        - Se o controle de duplicidade estiver fora do ar, a API responde `503`
          (`IDEMPOTENCY_UNAVAILABLE`) e **não cria** a nota. Reenvie depois.

        ### Acompanhar a autorização (webhook)

        Cadastre a URL de notificação nas configurações da empresa. A cada mudança de status a API envia

        um `POST` com `event_id`, `event`, `timestamp`, `message` e `nfse`. A tabela de eventos está em

        **Eventos do webhook**, no início desta documentação.


        - O mesmo status não é notificado duas vezes seguidas; depois de outro status, volta a notificar
          (ex.: `nfse_rejected`, retransmissão, `nfse_pending`, `nfse_processing`, `nfse_rejected`).
        - Os eventos **podem chegar fora de ordem** (cada um tem as próprias tentativas de reenvio). Use
          `timestamp` e consulte `GET /v2/invoices/nfse/{id}` para saber o status atual; só os eventos
          finais encerram o acompanhamento.
        - `event_id` é único por evento e se repete só nas novas tentativas de entrega do mesmo evento.

        - `nfse.previous_status` traz o último status notificado da nota (`null` quando não há registro).

        - Os status intermediários de cancelamento (`pending_cancellation`, `cancelling`) não geram evento.


        O objeto `nfse` traz `id`, `external_id`, `status`, `previous_status`, `message` (texto curto do status),

        `environment` (`producao` ou `homologacao`), `valor_servicos` (número), `numero_nfse`,

        `chave_acesso` (como a SEFIN devolve: prefixo `NFS` + 50 dígitos), `chave_acesso_digitos`

        (só os 50 dígitos), links absolutos de consulta/XML/PDF e, na rejeição, `error: {code, message}`

        (mesmo formato do webhook da NFCom) além da lista em `errors`. Mensagens da prefeitura vêm limitadas

        a 300 caracteres no webhook; o texto completo fica no histórico da nota (`GET /v2/invoices/nfse/{id}/logs`).


        O webhook é marcado como entregue só depois de uma resposta 2xx (ou ao esgotar as tentativas).

        Sem URL configurada nada é marcado.


        Cabeçalhos: `X-TelcomNFe-Event`, `X-TelcomNFe-Event-ID`, `X-TelcomNFe-NFSe-ID`, `X-TelcomNFe-Customer-ID`,

        `X-TelcomNFe-Signature` (legado) e, se a empresa tiver segredo, `X-TelcomNFe-Timestamp` e

        `X-TelcomNFe-Signature-256`. Veja **Webhooks → Validar a assinatura**.

        Sem webhook, consulte `GET /v2/invoices/nfse/{id}`.


        ### Limite de requisições

        Janela deslizante de 1 minuto, contada por empresa (token de integração) nas rotas de NFS-e:


        | Balde | Limite/min | O que conta | Headers |

        |---|---|---|---|

        | Total | 1.200 | toda requisição | `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` |

        | Escrita | 300 | toda requisição que não é `GET` (criar, lote, cancelar, substituir, retransmitir, importar,
        copiar, excluir, serviços, configurações…) | `X-RateLimit-Write-Limit`, `X-RateLimit-Write-Remaining`,
        `X-RateLimit-Write-Reset` |

        | Notas | 600 | notas emitidas: 1 por `/full`, `/full/sync`, `PUT /full/{id}`, retransmitir e substituir; **1
        por nota** do lote | `X-RateLimit-Notes-Limit`, `X-RateLimit-Notes-Remaining`, `X-RateLimit-Notes-Reset` |


        `*-Reset` é o fim do minuto corrente (Unix, segundos). Acima de qualquer limite a API responde

        `429` com `Retry-After` (segundos) e `error.details.bucket` (`nfse_all`, `nfse_write` ou `nfse_notes`);

        a requisição barrada não consome limite. Requisições recusadas por validação ou autenticação

        (`400`, `401`, `403`) também não contam. O token de login do painel tem limite próprio, por

        usuário, 5× maior.


        No balde de notas só conta o que gerou DPS: notas duplicadas (`duplicate: true`), criadas como

        rascunho ou recusadas antes do envio (`409`/`422`, inclusive itens do lote) são devolvidas ao

        fim da requisição.


        Token inválido, expirado, substituído ou revogado: depois de 30 respostas `401` no minuto a API

        responde `429` (`error.details.bucket: invalid_auth`) até a janela passar. Token sem assinatura válida conta

        por IP; token revogado (assinatura válida) conta só para ele mesmo. Um token aceito pela autenticação

        nunca é barrado por esse limite, mesmo vindo de um IP bloqueado. Quem errou o token recebe

        `X-RateLimit-Auth-Limit`, `X-RateLimit-Auth-Remaining` (já descontando a requisição atual: 29 na

        primeira) e `X-RateLimit-Auth-Reset`.
      requestBody:
        required: true
        content:
          application/json:
            schema: &a34
              type: object
              required:
                - competencia
                - client
                - items
              properties:
                competencia:
                  type: string
                  description: |
                    Competência `AAAA-MM-DD`, `AAAA-MM` ou `AAAAMM`. Não pode ser posterior à data de
                    emissão (regra E0015). Limites retroativos (convênio do município, inscrição do CNPJ/CPF,
                    cadastro municipal) são validados pelo Sistema Nacional na transmissão.
                  example: 2026-09-01
                dh_emi:
                  type: string
                  description: Data de emissão da DPS. Sem valor, usa o momento atual. Não pode ser futura (regra E0008).
                  example: 2026-09-28
                discriminacao:
                  type: string
                  maxLength: 2000
                  description: "Discriminação da nota (xDescServ). Pode vir com quebra de linha (\\n ou CRLF): a quebra vai na DPS e fica
                    na NFS-e autorizada e no DANFSe. CRLF vira LF, os espaços nas pontas de cada linha são removidos e
                    sobra no máximo uma linha em branco seguida. Até 2000 caracteres, contando cada quebra como 1; acima
                    disso a nota é recusada (422), sem corte. Se omitida, junta a discriminação dos itens, uma por
                    linha. Notas transmitidas antes ao ambiente antigo de Campinas (ADN da prefeitura) saíram com cada
                    quebra trocada por \" - \"."
                c_loc_prestacao:
                  type: string
                  description: IBGE do local da prestação (7 dígitos). Sem valor, usa o município do tomador.
                  example: "3509502"
                autoTransmit:
                  type: boolean
                  description: Padrão `true` (enfileira). `false` grava rascunho. Ignorado em `/full/sync`.
                  example: true
                external_id:
                  type: string
                  maxLength: 100
                  description: |
                    Identificador da nota no seu sistema (pedido, fatura, cobrança). Único por empresa e ambiente
                    (homologação/produção). Reenviar o mesmo `external_id` com o mesmo conteúdo **não cria outra
                    NFS-e**: a resposta volta com HTTP 200, `duplicate: true` e a nota já existente. Com conteúdo
                    diferente, a API responde 409 (`EXTERNAL_ID_CONFLICT`). Só espaços → 422 (`VALIDATION_ERROR`).
                    Também aceito pelo cabeçalho `Idempotency-Key` (o campo do corpo tem prioridade).
                  example: FAT-2026-000123
                client:
                  type: object
                  required:
                    - document
                    - name
                  properties:
                    document:
                      type: string
                      example: "12345678901"
                    name:
                      type: string
                      example: Cliente Exemplo LTDA
                    im:
                      type: string
                    email:
                      type: string
                    phone:
                      type: string
                    address:
                      type: object
                      description: >
                        Obrigatório para tomador com CNPJ (E0235), com ISS retido pelo tomador (E0237), para serviço

                        com ISS devido no local do tomador (17.05.01, E0234) e para os cIndOp que exigem endereço
                        (E0234).

                        Para tomador CPF fora desses casos pode ser omitido: a DPS sai sem o grupo `end`.

                        O CEP precisa ser da cidade informada (E0240), senão a API responde `422`.
                      properties:
                        street:
                          type: string
                        number:
                          type: string
                        complement:
                          type: string
                        district:
                          type: string
                        city:
                          type: string
                        state:
                          type: string
                          example: SP
                        zip_code:
                          type: string
                          example: "13010000"
                        city_code:
                          type: string
                          description: "IBGE com 7 dígitos. Opcional: vazio = descoberto pelo CEP (ou por city + state)."
                          example: "3509502"
                        country:
                          type: string
                          description: "Tomador no exterior (com `nif`): país em código ISO de 2 letras. Alternativa a `exterior.c_pais`."
                          example: US
                        province:
                          type: string
                          description: "Tomador no exterior: estado, província ou região (vai para `xEstProvReg`). Obrigatório com `nif`."
                          example: Florida
                    nif:
                      type: string
                      description: >
                        Tomador no exterior: NIF no lugar do CPF/CNPJ. Exige o país em `exterior.c_pais` ou

                        `client.address.country`. Logradouro, número, bairro, cidade e `zip_code` vão para o endereço no
                        exterior da DPS.

                        O leiaute exige no `endExt` código postal (`zip_code`), cidade (`city`) e estado/província
                        (`province`);

                        sem algum deles a API responde `422 VALIDATION_ERROR` (a SEFIN rejeitaria com E1235).

                        Com IBS/CBS tributado (CST que gera o grupo de tributação: 000, 010, 011, 200, 220, 221, 222,
                        510, 515,

                        550, 830) e cIndOp no local do tomador (010106, 100101, 100301, 100501), a SEFIN exige tomador
                        com

                        CPF/CNPJ e endereço no Brasil (E0239); a API responde `422 IBSCBS_TOMADOR_EXTERIOR`.

                        Para exportação de serviço informe `ibs_cst` "410" e `c_class_trib` "410027" no item
                        (`items[].ibs_cst`,

                        `items[].c_class_trib`) ou em `servico`. O campo se chama `ibs_cst`; `cst` não existe e volta
                        como não

                        permitido. Informando só `c_class_trib`, o CST sai dos 3 primeiros dígitos. Com CST que não gera

                        IBS/CBS (400, 410, 620, 800, 810, 811, 820) o `c_ind_op` é opcional e não vai na DPS do leiaute
                        NT 009

                        (a SEFIN recusaria com E0859).
                    update_registration:
                      type: boolean
                      default: false
                      description: |
                        Só para tomador já cadastrado. `true` atualiza nome, IM e endereço do cadastro com os dados
                        desta nota. Padrão: o cadastro não é alterado (a nota usa os dados enviados mesmo assim).
                    caepf:
                      type: string
                      pattern: ^\d{14}$
                      description: >
                        CAEPF do tomador (14 dígitos). Só vai na nota; o cadastro não é alterado.

                        Sem a chave, usa o CAEPF dos dados NFS-e do cliente (`PUT
                        /v2/invoices/nfse/clients/{clientId}/defaults`); `null` ou vazio = sem CAEPF.
                items:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - codigo_servico
                      - valor
                    properties:
                      codigo_servico:
                        type: string
                        pattern: ^[a-zA-Z0-9]{1,20}$
                        maxLength: 20
                        description: Código interno do serviço (`code` no cadastro) — 1 a 20 letras ou números. Também aceito em
                          `codigo_interno`.
                        example: "00001"
                      codigo_interno:
                        type: string
                        pattern: ^[a-zA-Z0-9]{1,20}$
                        maxLength: 20
                        description: Alias de `codigo_servico` (código interno do cadastro).
                      descricao:
                        type: string
                        maxLength: 2000
                        description: Descrição do serviço (xDescServ)
                      valor:
                        type: number
                        example: 150.9
                      discriminacao:
                        type: string
                      c_trib_nac:
                        type: string
                        example: "010101"
                      c_trib_mun:
                        type: string
                        description: Desdobro municipal de até 3 dígitos
                        example: "001"
                      c_nbs:
                        type: string
                        example: "115021000"
                      trib_issqn:
                        type: string
                        enum:
                          - "1"
                          - "2"
                          - "3"
                          - "4"
                      tp_ret_issqn:
                        type: string
                        enum:
                          - "1"
                          - "2"
                          - "3"
                      pis_cofins_cst:
                        type: string
                      pis_cofins_tp_ret:
                        type: string
                      pis_aliq:
                        type: number
                        minimum: 0
                        maximum: 99.99
                        description: Alíquota PIS (%) com até 2 casas decimais
                      cofins_aliq:
                        type: number
                        minimum: 0
                        maximum: 99.99
                        description: Alíquota COFINS (%) com até 2 casas decimais
                      ibs_cst:
                        type: string
                        example: "000"
                        description: >
                          CST do IBS/CBS (3 dígitos). Sem ele, vale o CST de `c_class_trib` (3 primeiros dígitos),
                          depois o do

                          cadastro do serviço. CST e classificação de grupos diferentes: 422 `IBSCBS_CST_CLASSTRIB`.
                      c_ind_op:
                        type: string
                        example: "100301"
                        description: >
                          Indicador da operação (cIndOp, 6 dígitos, Anexo VII). Sem ele, vale o do cadastro do serviço e
                          depois o da

                          tributação padrão. Sem nenhum dos três, a API responde 422 `CINDOP_REQUIRED` (não há valor
                          padrão),

                          exceto com CST que não gera IBS/CBS (400, 410, 620, 800, 810, 811, 820): aí ele é opcional e
                          não vai

                          na DPS do leiaute NT 009 (E0859).

                          Também define se a DPS exige tomador/endereço e, com 020101/020201/020301, o grupo
                          `ibscbs.imovel`.
                      c_class_trib:
                        type: string
                        example: "000001"
                        description: Classificação tributária do IBS/CBS (6 dígitos; os 3 primeiros são o CST).
                      c_int_contrib: &a29
                        type: string
                        pattern: ^[a-zA-Z0-9]{1,20}$
                        description: Código interno do contribuinte enviado na DPS (cIntContrib), 1 a 20 letras ou números.
                servico:
                  type: object
                  description: Sobrescreve os códigos fiscais da nota. Se omitido, usa o primeiro item.
                  properties:
                    c_int_contrib: *a29
                valores:
                  type: object
                  description: Retenções e deduções (vRetCSLL, vDescCond, etc.).
                  properties:
                    v_receb:
                      type: number
                      description: Valor recebido pelo intermediário (vReceb). Exige o bloco `interm`.
                    p_dr:
                      type: number
                      minimum: 0
                      maximum: 100
                      description: >
                        Percentual de dedução/redução da base (pDR). Use só um entre `vDedRed`, `p_dr` e
                        `documentos_ded_red`.

                        Em município com ADN próprio (ex.: Campinas), que não guarda o pDR na nota autorizada, o
                        percentual é enviado como valor (`vDR` = valor × p_dr / 100).
                    documentos_ded_red:
                      type: array
                      maxItems: 1000
                      description: >
                        Documentos de dedução/redução (até 1000). Use só um entre `vDedRed`, `p_dr` e
                        `documentos_ded_red`.

                        Cada documento tem exatamente um identificador: `ch_nfse`, `ch_nfe`, `nfse_mun`, `nf_nfs`,
                        `n_doc_fisc` ou `n_doc`.
                      items:
                        type: object
                        required:
                          - tp_ded_red
                          - dt_emi_doc
                          - v_dedutivel_redutivel
                          - v_deducao_reducao
                        properties:
                          ch_nfse:
                            type: string
                            pattern: ^\d{50}$
                          ch_nfe:
                            type: string
                            pattern: ^\d{44}$
                          nfse_mun:
                            type: object
                            required:
                              - c_mun
                              - n_nfse
                              - c_verif
                            properties:
                              c_mun:
                                type: string
                                pattern: ^\d{7}$
                              n_nfse:
                                type: string
                                pattern: ^\d{1,15}$
                              c_verif:
                                type: string
                                pattern: ^[a-zA-Z0-9]{1,9}$
                          nf_nfs:
                            type: object
                            required:
                              - n_nfs
                              - mod_nfs
                              - serie_nfs
                            properties:
                              n_nfs:
                                type: string
                                pattern: ^\d{1,7}$
                              mod_nfs:
                                type: string
                                pattern: ^\d{1,15}$
                              serie_nfs:
                                type: string
                                pattern: ^[a-zA-Z0-9]{1,15}$
                          n_doc_fisc:
                            type: string
                            maxLength: 255
                          n_doc:
                            type: string
                            maxLength: 255
                          tp_ded_red:
                            type: string
                            enum:
                              - "1"
                              - "2"
                              - "3"
                              - "4"
                              - "5"
                              - "6"
                              - "7"
                              - "8"
                              - "9"
                              - "99"
                          x_desc_out_ded:
                            type: string
                            maxLength: 150
                            description: Obrigatório quando `tp_ded_red` = 99.
                          dt_emi_doc:
                            type: string
                            format: date
                          v_dedutivel_redutivel:
                            type: number
                          v_deducao_reducao:
                            type: number
                          fornec: &a30
                            type: object
                            description: Pessoa (fornecedor). Informe um entre `document`, `nif` e `c_nao_nif`.
                            required:
                              - name
                            properties:
                              document:
                                type: string
                              nif:
                                type: string
                                maxLength: 40
                              c_nao_nif: &a31
                                type: string
                                enum:
                                  - "0"
                                  - "1"
                                  - "2"
                                description: "Motivo de não informar o NIF: 0 = não informado na nota de origem, 1 = dispensado, 2 = não exigido."
                              caepf:
                                type: string
                                pattern: ^\d{14}$
                              im:
                                type: string
                              name:
                                type: string
                              email:
                                type: string
                              fone:
                                type: string
                              address:
                                type: string
                              number:
                                type: string
                              complement:
                                type: string
                              district:
                                type: string
                              city_code:
                                type: string
                                pattern: ^\d{7}$
                              zip_code:
                                type: string
                    documentos_ajuste_bc:
                      type: array
                      maxItems: 1000
                      description: >
                        Documentos de ajuste da base de cálculo (`vAjusteBC/documentos/docAjusteBC`, até 1000), do
                        leiaute novo da

                        NFS-e (NT 009, DPS `2026-10`). Nesse leiaute substituem `documentos_ded_red`; enviar
                        `documentos_ded_red`

                        nele (ou `documentos_ajuste_bc` no leiaute anterior) responde `422 VALIDATION_ERROR` antes da
                        transmissão.

                        O leiaute em vigor no ambiente da empresa aparece em `dps_layout` (GET das configurações da
                        NFS-e).

                        Cada documento tem exatamente um identificador: `dfe_nacional`, `doc_fiscal_outro` ou
                        `doc_outro`.

                        `v_ajuste_aplic` não pode passar de `v_tot_doc`.


                        Empresa ME/EPP do Simples Nacional (opSimpNac 3, apuração pelo SN): a SEFIN só aceita
                        ajuste/dedução da base

                        nos subitens do Anexo VI (ex.: 07.02.01, 17.05.01) ou com documentos dos tipos 101 a 105 e 199
                        (E0451/E0452/E0455).

                        Fora disso, a API responde `422 AJUSTE_BC_SIMPLES` antes de transmitir.
                      items:
                        type: object
                        required:
                          - tp_ajuste_bc
                          - v_tot_doc
                          - v_ajuste_aplic
                        properties:
                          tp_ajuste_bc:
                            type: string
                            enum:
                              - "2"
                              - "5"
                              - "6"
                              - "7"
                              - "8"
                              - "9"
                              - "99"
                              - "101"
                              - "102"
                              - "103"
                              - "104"
                              - "105"
                              - "199"
                            description: >
                              Tipo do ajuste (tpAjusteBC). 101 a 105 e 199 são repasses e reembolsos (corretagem de
                              imóveis,

                              agência de turismo, produção externa de publicidade, reembolsos por conta e ordem de
                              terceiro).
                          x_tp_ajuste_bc:
                            type: string
                            maxLength: 150
                            description: Descrição do tipo
                            quando o tipo exigir.: null
                          v_tot_doc:
                            type: number
                            description: Valor total do documento.
                          v_ajuste_aplic:
                            type: number
                            description: Valor do ajuste aplicado nesta nota (até `v_tot_doc`).
                          dt_emi_doc:
                            type: string
                            format: date
                          dt_comp_doc:
                            type: string
                            format: date
                          dfe_nacional:
                            type: object
                            required:
                              - tipo_chave_dfe
                              - chave_dfe
                            properties:
                              tipo_chave_dfe:
                                type: string
                                enum:
                                  - "1"
                                  - "2"
                                  - "3"
                                  - "9"
                              x_tipo_chave_dfe:
                                type: string
                                maxLength: 255
                                description: Obrigatório quando `tipo_chave_dfe` = 9.
                              chave_dfe:
                                type: string
                                maxLength: 50
                          doc_fiscal_outro:
                            type: object
                            required:
                              - c_mun_doc_fiscal
                              - n_doc_fiscal
                              - x_doc_fiscal
                            properties:
                              c_mun_doc_fiscal:
                                type: string
                                pattern: ^\d{7}$
                              n_doc_fiscal:
                                type: string
                                maxLength: 255
                              x_doc_fiscal:
                                type: string
                                maxLength: 255
                          doc_outro:
                            type: object
                            required:
                              - n_doc
                              - x_doc
                            properties:
                              n_doc:
                                type: string
                                maxLength: 255
                              x_doc:
                                type: string
                                maxLength: 255
                          fornec: *a30
                    tot_trib:
                      type: object
                      description: >
                        Tributos aproximados (Lei 12.741/2012). Informe só um grupo: valores (`v_tot_trib_*`),

                        percentuais (`p_tot_trib_*`) ou `p_tot_trib_sn` (Simples Nacional). Sem a chave, usa a forma
                        padrão

                        da empresa (Configuração → NFS-e); sem padrão, a DPS sai com `indTotTrib` = 0. Envie `{
                        "ind_tot_trib": "0" }`

                        para não informar nesta nota mesmo havendo padrão.
                      properties:
                        v_tot_trib_fed:
                          type: number
                        v_tot_trib_est:
                          type: number
                        v_tot_trib_mun:
                          type: number
                        p_tot_trib_fed:
                          type: number
                        p_tot_trib_est:
                          type: number
                        p_tot_trib_mun:
                          type: number
                        p_tot_trib_sn:
                          type: number
                          maximum: 99.99
                        ind_tot_trib:
                          type: string
                          enum:
                            - "0"
                    trib_mun:
                      type: object
                      description: Campos opcionais da tributação municipal (ISS).
                      properties:
                        p_aliq:
                          type: number
                          maximum: 9.99
                          description: Alíquota do ISS (%). Só vai no XML quando informada; município parametrizado pode rejeitá-la (L0006).
                        tp_imunidade:
                          type: string
                          enum:
                            - "0"
                            - "1"
                            - "2"
                            - "3"
                            - "4"
                            - "5"
                          description: >
                            Tipo de imunidade. Só com `trib_issqn` = 2, e obrigatório nesse caso (sem ele e sem padrão
                            da empresa,

                            a API responde 422 `VALIDATION_ERROR` no campo `valores.trib_mun.tp_imunidade`: "Informe o
                            tipo de imunidade.").
                        exig_susp:
                          type: object
                          description: "Exigibilidade do ISS suspensa: 1 = decisão judicial, 2 = processo administrativo."
                          required:
                            - tp_susp
                            - n_processo
                          properties:
                            tp_susp:
                              type: string
                              enum:
                                - "1"
                                - "2"
                            n_processo:
                              type: string
                              pattern: ^\d{30}$
                        bm:
                          type: object
                          description: Benefício municipal. `v_red_bcbm` e `p_red_bcbm` são excludentes.
                          required:
                            - n_bm
                          properties:
                            n_bm:
                              type: string
                              pattern: ^\d{14}$
                            v_red_bcbm:
                              type: number
                            p_red_bcbm:
                              type: number
                        c_pais_result:
                          type: string
                          pattern: ^[A-Z]{2}$
                          description: País onde se verifica o resultado do serviço (ISO, 2 letras). Só com `trib_issqn` = 3.
                interm:
                  type: object
                  description: Intermediário. Obrigatório quando a retenção de ISS for por intermediário.
                  properties:
                    nif:
                      type: string
                      maxLength: 40
                    c_nao_nif: *a31
                    caepf:
                      type: string
                      pattern: ^\d{14}$
                obra:
                  type: object
                  description: |
                    Dados da obra (E0370/E0372). Obrigatório para construção civil (07.02.01, 07.02.02, 07.04.01,
                    07.05.01, 07.05.02, 07.06.01, 07.06.02, 07.07.01, 07.08.01, 07.17.01, 07.19.01) e 14.14.03/14.14.04;
                    opcional em 99.01.01; omitido nos demais `c_trib_nac`.
                atv_evento:
                  type: object
                  description: Atividade ou evento, quando a tributação nacional exigir.
                exterior:
                  type: object
                  properties:
                    c_nao_nif_tomador: *a31
                ibscbs:
                  type: object
                  properties:
                    tp_oper:
                      type: string
                      enum:
                        - "1"
                        - "2"
                        - "3"
                        - "4"
                        - "5"
                      description: Tipo de operação com entes governamentais.
                    tp_ente_gov:
                      type: string
                      enum:
                        - "1"
                        - "2"
                        - "3"
                        - "4"
                      description: "Tipo de ente governamental: 1 = União, 2 = Estado, 3 = Distrito Federal, 4 = Município."
                    ref_nfse:
                      type: array
                      maxItems: 99
                      description: Chaves (50 dígitos) das NFS-e referenciadas.
                      items:
                        type: string
                        pattern: ^\d{50}$
                    ree_rep_res:
                      type: array
                      maxItems: 1000
                      description: Documentos de reembolso, repasse ou ressarcimento. Cada documento tem um entre `dfe_nacional`,
                        `doc_fiscal_outro` e `doc_outro`.
                      items:
                        type: object
                        required:
                          - dt_emi_doc
                          - dt_comp_doc
                          - tp_ree_rep_res
                          - vlr_ree_rep_res
                        properties:
                          dfe_nacional:
                            type: object
                            required:
                              - tipo_chave_dfe
                              - chave_dfe
                            properties:
                              tipo_chave_dfe:
                                type: string
                                enum:
                                  - "1"
                                  - "2"
                                  - "3"
                                  - "9"
                              x_tipo_chave_dfe:
                                type: string
                                description: Obrigatório quando `tipo_chave_dfe` = 9.
                              chave_dfe:
                                type: string
                                maxLength: 50
                          doc_fiscal_outro:
                            type: object
                            required:
                              - c_mun_doc_fiscal
                              - n_doc_fiscal
                              - x_doc_fiscal
                            properties:
                              c_mun_doc_fiscal:
                                type: string
                                pattern: ^\d{7}$
                              n_doc_fiscal:
                                type: string
                              x_doc_fiscal:
                                type: string
                          doc_outro:
                            type: object
                            required:
                              - n_doc
                              - x_doc
                            properties:
                              n_doc:
                                type: string
                              x_doc:
                                type: string
                          fornec: *a30
                          dt_emi_doc:
                            type: string
                            format: date
                          dt_comp_doc:
                            type: string
                            format: date
                          tp_ree_rep_res:
                            type: string
                            enum:
                              - "01"
                              - "02"
                              - "03"
                              - "04"
                              - "99"
                          x_tp_ree_rep_res:
                            type: string
                            description: Obrigatório quando `tp_ree_rep_res` = 99.
                          vlr_ree_rep_res:
                            type: number
                    c_cred_pres:
                      type: string
                      pattern: ^\d{2}$
                      description: Código de crédito presumido.
                    trib_regular:
                      type: object
                      description: Tributação regular, aplicada se a condição da operação não se cumprir.
                      required:
                        - cst_reg
                        - c_class_trib_reg
                      properties:
                        cst_reg:
                          type: string
                          pattern: ^\d{3}$
                        c_class_trib_reg:
                          type: string
                          pattern: ^\d{6}$
                    dif:
                      type: object
                      description: Percentuais de diferimento de IBS (UF e município) e CBS.
                      required:
                        - p_dif_uf
                        - p_dif_mun
                        - p_dif_cbs
                      properties:
                        p_dif_uf:
                          type: number
                        p_dif_mun:
                          type: number
                        p_dif_cbs:
                          type: number
                    dest:
                      type: object
                      properties:
                        c_nao_nif: *a31
                info_compl:
                  type: object
                  description: Informações complementares da DPS.
                  properties:
                    id_doc_tec:
                      type: string
                      maxLength: 40
                      description: Identificador do documento técnico.
                    doc_ref:
                      type: string
                      maxLength: 255
                      description: Documento de referência.
                    x_ped:
                      type: string
                      maxLength: 60
                      description: Número do pedido ou ordem de compra.
                    itens_ped:
                      type: array
                      maxItems: 99
                      description: Itens do pedido (até 60 caracteres cada).
                      items:
                        type: string
                        maxLength: 60
                    x_inf_comp:
                      type: string
                      maxLength: 2000
                      description: >
                        Observações impressas na nota. Quebras de linha viram espaço. Sem a chave, usa a observação
                        padrão

                        do serviço e, sem ela, a da empresa; vazio = sem observação.

                        Em município com ADN próprio (ex.: Campinas), pedido, itens do pedido, CAEPF do tomador e
                        tributos do

                        Simples Nacional, que a prefeitura não guarda na nota autorizada, são repetidos aqui.
                com_ext:
                  type: object
                  description: Comércio exterior de serviços. Todos os campos são obrigatórios, exceto `n_di` e `n_re`.
                  properties:
                    md_prestacao:
                      type: string
                      enum:
                        - "0"
                        - "1"
                        - "2"
                        - "3"
                        - "4"
                    vinc_prest:
                      type: string
                      enum:
                        - "0"
                        - "1"
                        - "2"
                        - "3"
                        - "4"
                        - "5"
                        - "6"
                        - "9"
                    tp_moeda:
                      type: string
                      pattern: ^\d{3}$
                      description: Código BACEN da moeda.
                    v_serv_moeda:
                      type: number
                      description: Valor do serviço na moeda estrangeira.
                    mec_af_comex_p:
                      type: string
                      pattern: ^\d{2}$
                      description: Mecanismo de apoio do prestador (00 a 08).
                    mec_af_comex_t:
                      type: string
                      pattern: ^\d{2}$
                      description: Mecanismo de apoio do tomador (00 a 26).
                    mov_temp_bens:
                      type: string
                      enum:
                        - "0"
                        - "1"
                        - "2"
                        - "3"
                    n_di:
                      type: string
                      maxLength: 12
                    n_re:
                      type: string
                      maxLength: 12
                    mdic:
                      type: string
                      enum:
                        - "0"
                        - "1"
                emissao:
                  type: object
                  description: >
                    Emitente da DPS. Só `tp_emit` = 1 (prestador) é aceito: 2 (tomador) e 3 (intermediário) retornam
                    422,

                    porque a DPS é sempre assinada e emitida pela empresa cadastrada como prestadora.
                  properties:
                    tp_emit:
                      type: string
                      enum:
                        - "1"
                        - "2"
                        - "3"
                      default: "1"
                    c_motivo_emis_ti:
                      type: string
                      enum:
                        - "1"
                        - "2"
                        - "3"
                        - "4"
                    ch_nfse_rej:
                      type: string
                      pattern: ^\d{50}$
            examples:
              padrao: &a36
                summary: NFS-e com tomador e serviço
                value:
                  competencia: 2026-09-01
                  dh_emi: 2026-09-28
                  autoTransmit: true
                  client:
                    document: "12345678901"
                    name: Cliente Exemplo LTDA
                    email: cliente@exemplo.com
                    phone: "19999999999"
                    address:
                      street: Rua Exemplo
                      number: "100"
                      district: Centro
                      city: Campinas
                      state: SP
                      zip_code: "13010000"
                      city_code: "3509502"
                  items:
                    - codigo_servico: "00001"
                      descricao: Desenvolvimento de software
                      valor: 150.9
                      c_trib_nac: "010101"
                      c_trib_mun: "001"
                      c_nbs: "115021000"
                      trib_issqn: "1"
                      tp_ret_issqn: "1"
                      ibs_cst: "000"
                      c_ind_op: "100301"
                      c_class_trib: "000001"
      responses:
        "200":
          description: "`external_id` já recebido com o mesmo conteúdo. Devolve a NFS-e existente com `duplicate: true` (e
            `next_action` se ela estiver em rascunho/erro)."
          content:
            application/json:
              schema: &a32
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                  duplicate:
                    type: boolean
                    description: "`true` quando o `external_id` já existia; nenhuma nota nova foi criada."
                    example: false
                  id:
                    type: string
                    format: uuid
                  external_id:
                    type: string
                    nullable: true
                    example: FAT-2026-000123
                  status:
                    type: string
                    description: "`draft` quando não transmite; `pending` quando enfileirada."
                    example: pending
                  client:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      created:
                        type: boolean
                        description: "`true` quando o tomador foi cadastrado nesta chamada."
                  services:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        code:
                          type: string
                        created:
                          type: boolean
                  next_action:
                    type: object
                    description: >
                      Só na duplicata (`duplicate: true`) de uma nota em rascunho ou com erro de envio quando o reenvio

                      pediu transmissão. O reenvio não transmite: use este endpoint (ou `PUT
                      /v2/invoices/nfse/full/{id}`

                      para corrigir os dados antes).
                    properties:
                      action:
                        type: string
                        enum:
                          - retransmit
                        example: retransmit
                      method:
                        type: string
                        example: POST
                      path:
                        type: string
                        example: /v2/invoices/nfse/7b0e6c1e-2f43-4c6a-9d1e-3a1f0c2b9e10/retransmit
                      description:
                        type: string
                  document:
                    type: object
                    description: NFS-e gravada.
        "201":
          description: NFS-e criada (rascunho ou enfileirada)
          content:
            application/json:
              schema: *a32
        "400":
          description: "Cabeçalho ou JSON inválido (ex.: `Idempotency-Key` vazio — `EXTERNAL_ID_BLANK`; corpo que não é JSON —
            `INVALID_JSON`)."
          content:
            application/json:
              schema: &a33
                type: object
                description: |
                  Formato de todas as respostas de erro das rotas `/v2/invoices/nfse` (inclusive `401` e `429`).
                properties:
                  error: &a35
                    type: object
                    required:
                      - code
                      - message
                      - fields
                    properties:
                      code:
                        type: string
                        description: Código estável para tratar no seu sistema (ex.`VALIDATION_ERROR`, `EXTERNAL_ID_CONFLICT`, `RATE_LIMITED`,
                          `SETTINGS_PANEL_ONLY`, `NOT_FOUND`).
                        example: VALIDATION_ERROR
                      message:
                        type: string
                        description: Texto em português, pronto para exibir.
                        example: client.document é obrigatório.
                      fields:
                        type: array
                        description: Um item por campo inválido (vazio quando o erro não é de um campo).
                        items:
                          type: object
                          properties:
                            field:
                              type: string
                              description: Caminho do campo no corpo (ex. `items.0.valor`, `client.name`).
                              example: client.document
                            code:
                              type: string
                              enum:
                                - required
                                - invalid_type
                                - invalid_format
                                - invalid_length
                                - out_of_range
                                - invalid_value
                                - not_allowed
                                - invalid
                              example: required
                            message:
                              type: string
                              example: client.document é obrigatório.
                      details:
                        type: object
                        additionalProperties: true
                        description: Dados extras do erro, quando houver (ex. `id` da nota existente no `409`, `retry_after` e `bucket` no
                          `429`).
        "401":
          description: Token ausente, inválido ou expirado.
          content:
            application/json:
              schema: *a33
        "409":
          description: >
            `error.code = EXTERNAL_ID_CONFLICT`: o `external_id` já pertence a uma nota com conteúdo diferente
            (`error.details.id` = nota existente).

            `error.code = EXTERNAL_ID_IN_PROGRESS`: outra requisição com o mesmo `external_id` ainda está em
            processamento; tente de novo em instantes.
          content:
            application/json:
              schema: *a33
              example:
                error:
                  code: EXTERNAL_ID_CONFLICT
                  message: Este external_id já foi usado em outra NFS-e com dados diferentes. Use um external_id novo para uma nota nova,
                    ou consulte a nota existente.
                  fields: []
                  details:
                    id: 7b0e6c1e-2f43-4c6a-9d1e-3a1f0c2b9e10
                    external_id: PED-2026-0001
                    status: authorized
        "422":
          description: >
            Dados inválidos. Validação do corpo: `error.code = VALIDATION_ERROR` com um item em `error.fields`

            por campo. A mesma nota inválida dá o mesmo `422` e o mesmo `error` sozinha ou dentro do lote.

            `error.code = CINDOP_REQUIRED`: nem o item, nem o serviço, nem a tributação padrão têm o código do tipo de
            operação.
          content:
            application/json:
              schema: *a33
              examples:
                validacao:
                  summary: Campo inválido
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: valor deve ser maior que zero.
                      fields:
                        - field: items.0.valor
                          code: out_of_range
                          message: valor deve ser maior que zero.
                sem_cindop:
                  summary: Sem código do tipo de operação
                  value:
                    error:
                      code: CINDOP_REQUIRED
                      message: Informe o código do tipo de operação (cIndOp). Preencha no cadastro do serviço (seção Reforma tributária), na
                        tributação padrão ou na requisição.
                      fields:
                        - field: items.0.c_ind_op
                          code: required
                          message: Informe o código do tipo de operação (cIndOp). Preencha no cadastro do serviço (seção Reforma tributária), na
                            tributação padrão ou na requisição.
        "429":
          description: Limite de requisições atingido. Aguarde o tempo de `Retry-After`.
          content:
            application/json:
              schema: *a33
        "503":
          description: Controle de duplicidade indisponível (`IDEMPOTENCY_UNAVAILABLE`). A nota não foi criada; reenvie depois.
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/full/batch:
    post:
      tags:
        - NFS-e
      summary: Criar NFS-e em lote
      description: |
        Cria até **100 NFS-e** por requisição. Cada item de `notes` segue exatamente o contrato de
        `POST /v2/invoices/nfse/full` (inclusive `autoTransmit` e `external_id`).

        **A falha de uma nota não interrompe as demais.** As notas são processadas em paralelo
        (até 5 ao mesmo tempo) e `results` volta na mesma ordem de `notes`, com a posição em `index`.

        ### Envie `external_id` em todas as notas
        > **Importante:** sem `external_id`, reenviar o lote (ex.: após um timeout) emite as notas de novo.
        > Com ele, as já criadas voltam como `duplicate: true` e só as que faltaram são emitidas.
        > Notas criadas sem `external_id` voltam com `warning`.

        - `external_id` repetido **no mesmo lote**: a primeira nota segue; as outras falham com
          `status_code: 409`, `error.code: EXTERNAL_ID_REPEATED_IN_BATCH`.
        - `external_id` já usado com **conteúdo diferente**: o item falha com `status_code: 409`,
          `error.code: EXTERNAL_ID_CONFLICT` e o `id` da nota existente em `error.details.id`.
          Nada da nota existente é alterado.
        - `external_id` só com espaços: o item falha com `error.code: VALIDATION_ERROR`.

        ### Validação e erros
        - Envelope: `notes` precisa ter de 1 a 100 itens. Fora disso o lote inteiro é recusado com `422`
          (ex.: _"O lote aceita no máximo 100 notas por requisição (foram enviadas 101)…"_).
        - Cada nota é validada sozinha: nota malformada vira erro **só daquele item**.
        - O item recusado traz `status_code` e `error` (`code`, `message`, `fields`) iguais aos que a
          mesma nota teria em `POST /v2/invoices/nfse/full` sozinha.
        - Nota sem código do tipo de operação no item, no serviço e na tributação padrão: o item falha com
          `status_code: 422`, `error.code: CINDOP_REQUIRED`, e as outras notas seguem.

        ### Status HTTP
        `200` quando pelo menos uma nota foi aceita (confira `success` de cada item); `422` com
        `error.code: BATCH_ALL_FAILED` quando todas falharam. O lote consome 1 do limite de escrita e
        **1 do limite de notas por nota**.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - notes
              properties:
                notes:
                  type: array
                  minItems: 1
                  maxItems: 100
                  description: Cada item segue o contrato de `POST /full`; envie `external_id` único por nota.
                  items: *a34
      responses:
        "200":
          description: Lote processado (veja o resultado de cada nota)
          content:
            application/json:
              schema:
                type: object
                properties:
                  total:
                    type: integer
                    example: 3
                  created:
                    type: integer
                    example: 1
                  duplicates:
                    type: integer
                    example: 1
                  failed:
                    type: integer
                    example: 1
                  results:
                    type: array
                    items:
                      type: object
                      properties:
                        index:
                          type: integer
                          example: 0
                        success:
                          type: boolean
                        duplicate:
                          type: boolean
                        id:
                          type: string
                          format: uuid
                        external_id:
                          type: string
                          nullable: true
                        status:
                          type: string
                          example: pending
                        status_code:
                          type: integer
                          description: "Só nas falhas: o HTTP que a nota teria sozinha."
                          example: 422
                        error:
                          description: Só nas falhas (VALIDATION_ERROR, CINDOP_REQUIRED, EXTERNAL_ID_REPEATED_IN_BATCH, EXTERNAL_ID_CONFLICT,
                            EXTERNAL_ID_IN_PROGRESS, IDEMPOTENCY_UNAVAILABLE…).
                          allOf:
                            - *a35
                        next_action:
                          type: object
                          description: "Em duplicata de nota em rascunho/erro: como transmitir (retransmit) ou corrigir (PUT /full/{id})."
                        warning:
                          type: string
                          description: Nota criada sem external_id.
                        message:
                          type: string
                          description: Só nos sucessos.
              example:
                total: 3
                created: 1
                duplicates: 0
                failed: 2
                results:
                  - index: 0
                    success: true
                    duplicate: false
                    id: 7b0e6c1e-2f43-4c6a-9d1e-3a1f0c2b9e10
                    external_id: PED-1
                    status: pending
                    message: NFS-e criada e enviada para a fila de transmissão.
                  - index: 1
                    success: false
                    external_id: PED-2
                    status_code: 422
                    error:
                      code: VALIDATION_ERROR
                      message: valor deve ser maior que zero.
                      fields:
                        - field: items.0.valor
                          code: out_of_range
                          message: valor deve ser maior que zero.
                  - index: 2
                    success: false
                    external_id: PED-1
                    status_code: 409
                    error:
                      code: EXTERNAL_ID_REPEATED_IN_BATCH
                      message: O external_id "PED-1" já foi usado na nota de índice 0 deste lote. Cada nota do lote precisa de um external_id
                        próprio.
                      fields: []
        "401":
          description: Token ausente, inválido ou expirado.
          content:
            application/json:
              schema: *a33
        "422":
          description: |
            Envelope inválido (`notes` ausente, vazio ou com mais de 100 notas: `VALIDATION_ERROR`) ou
            nenhuma nota do lote aceita (`BATCH_ALL_FAILED`, com `results`).
          content:
            application/json:
              schema: *a33
        "429":
          description: Limite de requisições atingido (veja `Retry-After`)
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/full/sync:
    post:
      tags:
        - NFS-e
      summary: Criar NFS-e e enfileirar a transmissão
      description: |
        Mesmo contrato de `POST /v2/invoices/nfse/full`, sempre enfileirando a transmissão
        (ignora `autoTransmit: false`).

        **Apesar do nome, não é síncrona:** a NFS-e não espera a autorização da SEFIN nesta
        requisição. A resposta volta com status `pending` e a autorização segue pela fila, como na
        emissão pela tela. Acompanhe pelo webhook ou por `GET /v2/invoices/nfse/{id}`.
        `external_id` funciona igual ao `POST /full`.
      requestBody:
        required: true
        content:
          application/json:
            schema: *a34
            examples:
              padrao: *a36
      responses:
        "201":
          description: NFS-e criada e enfileirada
          content:
            application/json:
              schema: *a32
        "401":
          description: Não autorizado
        "422":
          description: Dados fiscais ou cadastrais inválidos
  /v2/invoices/nfse/full/{id}:
    put:
      tags:
        - NFS-e
      summary: Atualizar NFS-e completa
      description: |
        Substitui os dados de uma NFS-e em `draft` ou `error`.
        O body é o mesmo de `POST /v2/invoices/nfse/full`.

        Tomador e serviços seguem a mesma regra: cadastra se não existir, atualiza se existir.
        Por padrão a nota atualizada volta para a fila. Envie `autoTransmit: false` para manter o rascunho.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
          description: ID da NFS-e em rascunho ou com erro de envio
      requestBody:
        required: true
        content:
          application/json:
            schema: *a34
            examples:
              padrao: *a36
      responses:
        "200":
          description: NFS-e atualizada
          content:
            application/json:
              schema: *a32
        "401":
          description: Não autorizado
        "422":
          description: Nota não pode ser alterada ou dados inválidos
  /v2/invoices/nfse/usage:
    get:
      tags:
        - NFS-e Consultas
      summary: Consumo de NFS-e no mês
      description: |
        Quantidade de NFS-e emitidas no mês (horário de Brasília) comparada com a franquia do plano.

        `emitidas` conta as notas autorizadas **em produção** no mês, inclusive as canceladas ou
        substituídas depois. O mês é o da **data de autorização** (nota criada em 31/10 e autorizada
        em 01/11 conta em novembro). Notas de homologação — e qualquer nota sem ambiente de produção
        (`environment` diferente de `producao`, inclusive vazio) — aparecem só em `homologacao` e não contam
        na franquia.
      parameters:
        - name: month
          in: query
          required: false
          schema:
            type: string
            example: 2026-10
          description: "Mês no formato `AAAA-MM`. Padrão: mês atual."
      responses:
        "200":
          description: Consumo do mês
          content:
            application/json:
              schema:
                type: object
                properties:
                  month:
                    type: string
                    example: 2026-10
                  timezone:
                    type: string
                    example: America/Sao_Paulo
                  emitidas:
                    type: integer
                    example: 812
                  canceladas:
                    type: integer
                    example: 4
                  substituidas:
                    type: integer
                    example: 2
                  homologacao:
                    type: integer
                    example: 37
                  plano:
                    type: object
                    properties:
                      code:
                        type: string
                        nullable: true
                        example: SD-103
                      notas_incluidas:
                        type: integer
                        nullable: true
                        example: 1000
                  excedente:
                    type: integer
                    example: 0
                  percentual_usado:
                    type: number
                    nullable: true
                    example: 81.2
        "401":
          description: Não autorizado
        "422":
          description: Mês inválido
  /v2/invoices/nfse:
    get:
      tags:
        - NFS-e Consultas
      summary: Listar NFS-e
      description: |
        Lista as NFS-e da empresa, da mais nova para a mais antiga.

        **Paginação:** com o token de integração a lista é sempre paginada: sem `page`/`limit` vem a
        primeira página com 50 notas. Envie `page` e `limit` (máximo 500) para as próximas. O corpo é um
        array; o total vem no cabeçalho `X-Total-Count` (e `X-Page`, `X-Limit`).

        **Filtros:** `status` (um ou mais, separados por vírgula), `environment` e `external_id`.

        Cada item traz o status, o número, a chave de acesso, o `external_id`, o tomador, `created_at` e
        `authorized_at`. Os XMLs não vêm na listagem. Use `GET /v2/invoices/nfse/{id}/xml`.
      parameters:
        - name: page
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
          description: Página (começa em 1).
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 500
          description: Itens por página (padrão 50, máximo 500; acima disso responde 422 `INVALID_PAGINATION`).
        - name: status
          in: query
          required: false
          schema:
            type: string
            example: authorized,pending_consult
          description: |
            Um ou mais status separados por vírgula (`draft`, `pending`, `processing`, `pending_consult`,
            `authorized`, `error`, `pending_cancellation`, `cancelling`, `canceled`, `cancellation_error`,
            `substituted`). Status desconhecido → `422 INVALID_STATUS`.
        - name: external_id
          in: query
          required: false
          schema:
            type: string
          description: Filtra pela NFS-e criada com este `external_id`.
        - name: environment
          in: query
          required: false
          schema:
            type: string
            enum:
              - producao
              - homologacao
          description: Ambiente das notas (também aceita `1` e `2`). Valor desconhecido → `422 INVALID_ENVIRONMENT`.
      responses:
        "200":
          description: Lista de NFS-e
          headers:
            X-Total-Count:
              description: Total de notas com os filtros aplicados.
              schema:
                type: integer
            X-Page:
              schema:
                type: integer
            X-Limit:
              schema:
                type: integer
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                    n_dps:
                      type: integer
                    numero_nfse:
                      type: string
                      nullable: true
                    competencia:
                      type: string
                      format: date
                    valor_servicos:
                      type: number
                      example: 109
                    status: &a38
                      type: string
                      enum:
                        - draft
                        - pending
                        - processing
                        - pending_consult
                        - authorized
                        - error
                        - pending_cancellation
                        - cancelling
                        - canceled
                        - cancellation_error
                        - substituted
                      description: >
                        | Status | Significado |

                        |---|---|

                        | `draft` | Rascunho, ainda não enfileirada |

                        | `pending` | Na fila de transmissão |

                        | `processing` | DPS enviada, aguardando retorno |

                        | `pending_consult` | A prefeitura recebeu a DPS mas não confirmou o resultado; o sistema
                        consulta de novo sozinho. Não retransmita |

                        | `authorized` | NFS-e autorizada |

                        | `error` | Rejeitada ou falha no envio |

                        | `pending_cancellation` | Cancelamento enfileirado |

                        | `cancelling` | Cancelando |

                        | `canceled` | Cancelada |

                        | `cancellation_error` | Falha no cancelamento |

                        | `substituted` | Substituída por outra NFS-e |
                    environment: &a37
                      type: string
                      enum:
                        - producao
                        - homologacao
                      description: Ambiente em que a nota foi emitida.
                      example: homologacao
                    chave_acesso:
                      type: string
                      nullable: true
                    serie:
                      type: string
                    errors:
                      type: array
                      nullable: true
                      items:
                        type: object
                    external_id:
                      type: string
                      nullable: true
                      description: Identificador enviado pelo integrador na criação.
                    created_at:
                      type: string
                      format: date-time
                    authorized_at:
                      type: string
                      format: date-time
                      nullable: true
                      description: Data/hora da autorização pela SEFIN (null se ainda não autorizada).
                    client_id:
                      type: string
                      format: uuid
                      nullable: true
                    tomador_name:
                      type: string
                      nullable: true
                    tomador_document:
                      type: string
                      nullable: true
                    has_client_email:
                      type: boolean
                      description: "`true` quando o tomador tem e-mail para receber a nota."
                    snapshot:
                      type: object
        "401":
          description: Não autorizado
        "403":
          description: Módulo NFS-e não habilitado para a empresa
        "422":
          description: |
            Parâmetro de consulta inválido: `page`/`limit` (`INVALID_PAGINATION`), `status` (`INVALID_STATUS`)
            ou `environment` (`INVALID_ENVIRONMENT`).
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/{id}:
    get:
      tags:
        - NFS-e Consultas
      summary: Consultar NFS-e por ID
      description: |
        Retorna uma NFS-e com status, número, chave de acesso, erros e os dados usados na emissão.

        Use para acompanhar a nota depois de `POST /v2/invoices/nfse/full`.
        Quando `status` for `authorized`, `numero_nfse` e `chave_acesso` estão preenchidos.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: NFS-e encontrada
          content:
            application/json:
              schema: &a39
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  client_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: Tomador cadastrado.
                  nfse_service_id:
                    type: string
                    format: uuid
                    nullable: true
                    description: Serviço principal da nota.
                  environment: *a37
                  serie:
                    type: string
                    example: "10001"
                  n_dps:
                    type: integer
                    description: Número da DPS.
                    example: 652
                  competencia:
                    type: string
                    format: date
                    example: 2026-09-01
                  valor_servicos:
                    type: number
                    description: Valor total dos serviços, em reais (número, não texto).
                    example: 109
                  discriminacao:
                    type: string
                  c_loc_emi:
                    type: string
                    description: Código IBGE do município emissor.
                    example: "3509502"
                  c_loc_prestacao:
                    type: string
                    nullable: true
                  status: *a38
                  numero_nfse:
                    type: string
                    nullable: true
                    description: Número da NFS-e, preenchido após a autorização.
                    example: "3183"
                  authorized_at:
                    type: string
                    format: date-time
                    nullable: true
                    description: Data/hora da autorização pela SEFIN (base do consumo mensal).
                    example: 2026-09-02T14:31:07.000Z
                  chave_acesso:
                    type: string
                    nullable: true
                    description: |
                      Chave de acesso como a SEFIN/ADN devolve: prefixo `NFS` + 50 dígitos (53 caracteres).
                      Para só os dígitos, remova o prefixo (o webhook já traz `chave_acesso_digitos`).
                    example: NFS35095021245959033000100000000000318326096038523121
                  protocol:
                    type: string
                    nullable: true
                    example: adn_dps
                  external_id:
                    type: string
                    nullable: true
                    description: Identificador enviado pelo integrador na criação.
                  errors:
                    type: array
                    nullable: true
                    description: |
                      Rejeições devolvidas pela prefeitura ou pela SEFIN (cada `mensagem` limitada a 500 caracteres;
                      o texto completo fica no histórico da nota).
                    items:
                      type: object
                      properties:
                        codigo:
                          type: string
                          description: Código original da prefeitura/SEFIN (ex. `L0013`, `E0014`).
                        mensagem:
                          type: string
                          description: Mensagem original da prefeitura/SEFIN.
                        mensagem_simples:
                          type: string
                          description: A mesma rejeição em linguagem simples, pronta para mostrar ao usuário.
                  snapshot:
                    type: object
                    description: |
                      Dados usados na emissão (tomador, serviço, valores), já com os padrões cadastrados aplicados.
                      `defaults_applied` lista os campos que vieram de um padrão (ex. `info_compl.x_inf_comp:servico`).
                      Não inclui os XMLs nem dados internos do gateway.
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
    delete:
      tags:
        - NFS-e
      summary: Excluir NFS-e
      description: |
        Exclui uma NFS-e em `draft` ou `error`.
        Notas autorizadas não podem ser excluídas. Use o cancelamento ou a substituição.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "204":
          description: NFS-e excluída
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
        "422":
          description: Só é possível excluir rascunhos ou notas com erro de envio
  /v2/invoices/nfse/{id}/logs:
    get:
      tags:
        - NFS-e Consultas
      summary: Histórico da NFS-e
      description: >
        Eventos de processamento da NFS-e (envio, autorização, rejeição, cancelamento), do mais recente para o mais
        antigo.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Eventos da NFS-e
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    nfseDocumentId:
                      type: string
                      format: uuid
                    eventType:
                      type: string
                      example: Autorização
                    statusCode:
                      type: string
                      example: AUTHORIZED
                    statusMessage:
                      type: string
                      example: NFS-e autorizada nº 3183
                    attemptNumber:
                      type: integer
                    success:
                      type: boolean
                    processingMode:
                      type: string
                      example: automatic
                    protocolNumber:
                      type: string
                      nullable: true
                    createdAt:
                      type: string
                      format: date-time
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
  /v2/invoices/nfse/{id}/refresh:
    post:
      tags:
        - NFS-e Consultas
      summary: Atualizar situação da NFS-e
      description: |
        Consulta a situação atual da nota na prefeitura ou na SEFIN nacional e atualiza o registro.

        Use quando a nota ficar em `processing` por mais tempo que o normal. Notas em `pending_consult`
        já são consultadas automaticamente (a cada poucos minutos, com intervalo crescente); esta rota
        só antecipa a consulta.

        Se a consulta falhar, a nota não muda e nenhum webhook é enviado.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: NFS-e com a situação atualizada
          content:
            application/json:
              schema: *a39
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
  /v2/invoices/nfse/{id}/retransmit:
    post:
      tags:
        - NFS-e
      summary: Retransmitir NFS-e
      description: >
        Transmite de novo uma nota em `draft`, `error` ou `pending_consult`, com os dados gravados (use

        `PUT /v2/invoices/nfse/full/{id}` antes, se precisar corrigir algo).


        - A resposta volta `202` com `status: pending`; o resultado chega pelo webhook.

        - Nota em `pending_consult`: a DPS é consultada primeiro no endpoint onde foi transmitida e, sem resposta,
          no ambiente nacional. Se ela já virou NFS-e desta nota, o resultado é aplicado e nada é reenviado (`201`).
          Se não existir, responde `409 NFSE_RETRANSMIT_CONFIRM_NEW_NUMBER`; com `confirm_new_number: true` a nota
          é emitida com um número novo.
        - Se a prefeitura já recebeu essa DPS (E0014) e não respondeu à consulta, a DPS é procurada pelo Id
          no ambiente nacional. Se ela aparecer lá, o resultado é aplicado à nota.
        - Se a DPS não aparecer no ambiente nacional, responde `409 NFSE_RETRANSMIT_CONFIRM_NEW_NUMBER`.
          Para emitir com um número novo, repita a chamada com `{ "confirm_new_number": true }`. Confira antes
          no portal da prefeitura: nota emitida só no sistema municipal pode não constar no ambiente nacional.
        - Se nem o ambiente nacional responder, responde `409 NFSE_RETRANSMIT_PENDING_CONSULT` e não gera um número
        novo.

        - Quando a retransmissão é barrada na validação (`422`), o status da nota não muda: uma nota em
          `pending_consult` continua em `pending_consult`.
        - Nota gravada no leiaute anterior com `valores.documentos_ded_red` e emitida no leiaute NT 009: os documentos
          são convertidos para `valores.documentos_ajuste_bc` (chave de NFS-e/NF-e em `dfe_nacional`, NFS-e municipal
          em `doc_fiscal_outro`, documento não fiscal em `doc_outro`; mesmo tipo, valores e data). O que não tem
          correspondência (tipos 1, 3 e 4, ou nota fiscal sem o município) volta em `422 LEIAUTE_NT009`, com o que
          ajustar em `error.fields`.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                confirm_new_number:
                  type: boolean
                  description: Confirma emitir com um número novo depois de `409 NFSE_RETRANSMIT_CONFIRM_NEW_NUMBER`.
      responses:
        "201":
          description: A consulta mostrou que a DPS já tinha virado NFS-e (`authorized`); nada foi reenviado.
          content:
            application/json:
              schema: *a39
        "202":
          description: NFS-e enfileirada para transmissão
          content:
            application/json:
              schema: *a39
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
          content:
            application/json:
              schema: *a33
        "409":
          description: >
            `NFSE_RETRANSMIT_CONFIRM_NEW_NUMBER`: a DPS não aparece no ambiente nacional; reenvie com
            `confirm_new_number: true` para usar outro número.

            `NFSE_RETRANSMIT_PENDING_CONSULT`: nem a prefeitura nem o ambiente nacional confirmaram o resultado da DPS.
          content:
            application/json:
              schema: *a33
        "422":
          description: >
            Só é possível retransmitir rascunhos, notas com erro de envio ou aguardando consulta.

            `error.code = CINDOP_REQUIRED`: a nota, o serviço e a tributação padrão estão sem o código do tipo de
            operação.

            `error.code = LEIAUTE_NT009`: documentos de dedução do leiaute anterior sem conversão automática.

            `error.code = NBS_REQUIRED`: serviço 99.01.01 sem NBS (E0322).
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/services:
    get:
      tags:
        - NFS-e
      summary: Listar serviços da NFS-e
      description: |
        Lista os serviços da NFS-e cadastrados na empresa, em ordem de código. O `code` é o **código interno**
        usado em `POST /v2/invoices/nfse/full` como `codigo_servico` (alias `codigo_interno`).
      responses:
        "200":
          description: Serviços da empresa
          content:
            application/json:
              schema:
                type: array
                items: &a41
                  allOf:
                    - &a40
                      type: object
                      required:
                        - code
                        - description
                        - suggested_value
                      properties:
                        code:
                          type: string
                          description: Código interno do serviço (1 a 20 letras ou números). É o `codigo_servico` (e o alias `codigo_interno`) das
                            notas.
                          example: INTERNET100
                        description:
                          type: string
                          example: Plano de internet 100 Mb
                        suggested_value:
                          type: number
                          example: 109
                        enabled:
                          type: boolean
                          default: true
                        c_trib_nac:
                          type: string
                          description: Código de tributação nacional (6 dígitos).
                          example: "010701"
                        c_trib_mun:
                          type: string
                          nullable: true
                        c_nbs:
                          type: string
                          example: "115022000"
                        c_ind_op:
                          type: string
                          description: Indicador da operação padrão deste serviço (cIndOp). Na emissão da nota o valor pode ser alterado; use
                            "Salvar como padrão deste serviço" para gravar de volta aqui.
                        c_class_trib:
                          type: string
                        ibs_cst:
                          type: string
                        pis_cofins_cst:
                          type: string
                          nullable: true
                        pis_cofins_tp_ret:
                          type: string
                          nullable: true
                        pis_aliq:
                          type: number
                          nullable: true
                        cofins_aliq:
                          type: number
                          nullable: true
                        trib_issqn:
                          type: string
                          enum:
                            - "1"
                            - "2"
                            - "3"
                            - "4"
                        tp_ret_issqn:
                          type: string
                          enum:
                            - "1"
                            - "2"
                            - "3"
                        c_loc_prestacao:
                          type: string
                          nullable: true
                        c_int_contrib:
                          type: string
                          nullable: true
                          pattern: ^[a-zA-Z0-9]{1,20}$
                          description: Código interno enviado na nota (cIntContrib) quando a nota não informa `servico.c_int_contrib`.
                        obs_nota:
                          type: string
                          nullable: true
                          maxLength: 2000
                          description: Observação padrão da nota com este serviço (usada se a nota não tiver observação; tem prioridade sobre a da
                            empresa).
                        p_aliq:
                          type: number
                          nullable: true
                          maximum: 9.99
                          description: Alíquota do ISS (%) enviada quando a nota não informa `valores.trib_mun.p_aliq`. Deixe vazio se a
                            prefeitura aplica a dela.
                        beneficio_municipal:
                          type: object
                          nullable: true
                          description: Benefício municipal padrão (tem prioridade sobre o da empresa). `v_red_bcbm` e `p_red_bcbm` são
                            excludentes.
                          required:
                            - n_bm
                          properties:
                            n_bm:
                              type: string
                              pattern: ^\d{14}$
                            v_red_bcbm:
                              type: number
                              nullable: true
                            p_red_bcbm:
                              type: number
                              nullable: true
                        ibscbs_defaults:
                          type: object
                          nullable: true
                          description: Padrões de IBS/CBS (reforma tributária, a partir de 2027) usados quando a nota não informa.
                          properties:
                            c_cred_pres:
                              type: string
                              pattern: ^\d{2}$
                              nullable: true
                            trib_regular:
                              type: object
                              nullable: true
                              required:
                                - cst_reg
                                - c_class_trib_reg
                              properties:
                                cst_reg:
                                  type: string
                                  pattern: ^\d{3}$
                                c_class_trib_reg:
                                  type: string
                                  pattern: ^\d{6}$
                            dif:
                              type: object
                              nullable: true
                              required:
                                - p_dif_uf
                                - p_dif_mun
                                - p_dif_cbs
                              properties:
                                p_dif_uf:
                                  type: number
                                p_dif_mun:
                                  type: number
                                p_dif_cbs:
                                  type: number
                    - type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
        "401":
          description: Não autorizado
    post:
      tags:
        - NFS-e
      summary: Cadastrar serviço da NFS-e
      description: |
        Cadastra um serviço para usar nas notas. Também é possível deixar o `POST /v2/invoices/nfse/full`
        cadastrar o serviço na primeira nota que usar um `codigo_servico` (ou `codigo_interno`) novo.
        Excluir serviços só pelo painel (`403 SETTINGS_PANEL_ONLY` com o token de integração).
      requestBody:
        required: true
        content:
          application/json:
            schema: *a40
      responses:
        "201":
          description: Serviço cadastrado
          content:
            application/json:
              schema: *a41
        "401":
          description: Não autorizado
        "422":
          description: Dados inválidos
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/services/{id}:
    put:
      tags:
        - NFS-e
      summary: Atualizar serviço da NFS-e
      description: Atualiza um serviço da empresa. As notas já emitidas não mudam.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do serviço (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema: *a40
      responses:
        "200":
          description: Serviço atualizado
          content:
            application/json:
              schema: *a41
        "401":
          description: Não autorizado
        "404":
          description: Serviço não encontrado
          content:
            application/json:
              schema: *a33
        "422":
          description: Dados inválidos
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/clients/{clientId}/defaults:
    parameters:
      - name: clientId
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: Id do cliente (tomador) cadastrado.
    get:
      tags:
        - NFS-e
      summary: Consultar dados NFS-e do cliente
      description: |
        Dados do cliente usados só na NFS-e (NIF, CAEPF, órgão público, observação padrão).
        Cliente sem dados cadastrados devolve todos os campos `null`.
      responses:
        "200":
          description: Dados NFS-e do cliente
          content:
            application/json:
              schema: &a42
                type: object
                description: |
                  Dados do cliente usados só na NFS-e. Entram na nota quando a nota não informa o campo
                  (vazio ou `null` na nota = sem valor).
                properties:
                  client_id:
                    type: string
                    format: uuid
                    readOnly: true
                  nif:
                    type: string
                    nullable: true
                    maxLength: 40
                    description: NIF do cliente no exterior. Excludente com `c_nao_nif`.
                  c_nao_nif:
                    type: string
                    nullable: true
                    enum:
                      - "0"
                      - "1"
                      - "2"
                    description: "Motivo de não ter NIF: 0 = não informado na origem, 1 = dispensado, 2 = não exigido."
                  caepf:
                    type: string
                    nullable: true
                    pattern: ^\d{14}$
                    description: CAEPF (pessoa física com atividade econômica).
                  tp_ente_gov:
                    type: string
                    nullable: true
                    enum:
                      - "1"
                      - "2"
                      - "3"
                      - "4"
                    description: "Órgão público: 1 = União, 2 = Estado, 3 = Distrito Federal, 4 = Município. Vazio = não é órgão público."
                  tp_oper:
                    type: string
                    nullable: true
                    enum:
                      - "1"
                      - "2"
                      - "3"
                      - "4"
                      - "5"
                    description: Tipo de operação com órgão público. Exige `tp_ente_gov`.
                  c_end_post:
                    type: string
                    nullable: true
                    maxLength: 11
                    description: >
                      Cliente estrangeiro: código postal no exterior (`endExt/cEndPost`). Fica aqui porque o endereço do
                      cadastro do

                      estrangeiro é gravado como EXTERIOR/EX para a NFC-om. Entra na nota quando `exterior.c_end_post`
                      não vem.
                  x_cidade:
                    type: string
                    nullable: true
                    maxLength: 60
                    description: "Cliente estrangeiro: cidade no exterior (`endExt/xCidade`)."
                  x_est_prov_reg:
                    type: string
                    nullable: true
                    maxLength: 60
                    description: "Cliente estrangeiro: estado, província ou região (`endExt/xEstProvReg`)."
        "401":
          description: Não autorizado
        "404":
          description: Cliente não encontrado
          content:
            application/json:
              schema: *a33
    put:
      tags:
        - NFS-e
      summary: Salvar dados NFS-e do cliente
      description: |
        Grava os dados NFS-e do cliente (substitui os anteriores). Não altera o cadastro do cliente usado na NFC-om.
      requestBody:
        required: true
        content:
          application/json:
            schema: *a42
      responses:
        "200":
          description: Dados salvos
          content:
            application/json:
              schema: *a42
        "401":
          description: Não autorizado
        "404":
          description: Cliente não encontrado
        "422":
          description: Dados inválidos (ex. NIF e motivo juntos, tipo de operação sem órgão público)
          content:
            application/json:
              schema: *a33
  /v2/invoices/nfse/{id}/cancel:
    post:
      tags:
        - NFS-e
      summary: Cancelar NFS-e
      description: |
        Enfileira o cancelamento de uma NFS-e autorizada.

        A resposta volta com `status: pending_cancellation`. Acompanhe o resultado por
        `GET /v2/invoices/nfse/{id}`: a nota passa para `canceled` ou `cancellation_error`.

        Para corrigir valor ou dados de uma nota autorizada, prefira
        `POST /v2/invoices/nfse/{id}/substitute`.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e autorizada (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - c_motivo
                - x_motivo
              properties:
                c_motivo:
                  type: string
                  enum:
                    - "1"
                    - "2"
                    - "9"
                  description: |
                    - `1` erro na emissão
                    - `2` serviço não prestado
                    - `9` outros
                x_motivo:
                  type: string
                  minLength: 15
                  maxLength: 255
                  description: Justificativa do cancelamento.
            example:
              c_motivo: "1"
              x_motivo: Nota emitida com valor incorreto
      responses:
        "202":
          description: Cancelamento enfileirado
          content:
            application/json:
              schema: *a39
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
        "422":
          description: NFS-e não pode ser cancelada no status atual
  /v2/invoices/nfse/{id}/substitute:
    post:
      tags:
        - NFS-e
      summary: Substituir NFS-e
      description: |
        Emite uma nova NFS-e que substitui uma nota autorizada. Use para corrigir valor,
        tomador ou discriminação sem cancelar antes.

        Quando a nova nota é autorizada, a original passa para `substituted`.
        A resposta traz a **nova** NFS-e, normalmente em `pending` ou `processing`.

        `client_id` e `nfse_service_id` são os IDs devolvidos por `POST /v2/invoices/nfse/full`
        (`client.id` e `services[].id`).
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e autorizada que será substituída (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - client_id
                - competencia
                - discriminacao
                - c_motivo
              properties:
                client_id:
                  type: string
                  format: uuid
                  description: Tomador da nova nota.
                competencia:
                  type: string
                  format: date
                  example: 2026-09-02
                dh_emi:
                  type: string
                  description: Data de emissão (AAAA-MM-DD). Padrão é agora.
                discriminacao:
                  type: string
                  maxLength: 2000
                c_loc_prestacao:
                  type: string
                  pattern: ^\d{7}$
                  description: Código IBGE do local da prestação.
                c_motivo:
                  type: string
                  enum:
                    - "01"
                    - "02"
                    - "03"
                    - "04"
                    - "05"
                    - "99"
                  description: |
                    - `01` desenquadramento do Simples Nacional
                    - `02` enquadramento no Simples Nacional
                    - `03` inclusão retroativa de imunidade ou isenção
                    - `04` exclusão retroativa de imunidade ou isenção
                    - `05` rejeição da NFS-e pelo tomador ou intermediário
                    - `99` outros
                x_motivo:
                  type: string
                  minLength: 15
                  maxLength: 255
                  description: Justificativa. Obrigatória quando `c_motivo` é `99`.
                nfse_service_id:
                  type: string
                  format: uuid
                  description: Serviço da nota. Use com `valor` quando houver um único item.
                valor:
                  type: number
                  minimum: 0.01
                items:
                  type: array
                  description: Use no lugar de `nfse_service_id` e `valor` para mais de um serviço.
                  items:
                    type: object
                    required:
                      - nfse_service_id
                      - valor
                    properties:
                      nfse_service_id:
                        type: string
                        format: uuid
                      valor:
                        type: number
                        minimum: 0.01
                      discriminacao:
                        type: string
                        maxLength: 2000
                tomador:
                  type: object
                  description: Sobrescreve dados do tomador só nesta nota (nome, e-mail, endereço).
                servico:
                  type: object
                  description: Sobrescreve códigos fiscais do serviço só nesta nota.
            example:
              client_id: 3f0c1d52-7a55-4c0a-9b8e-2a1f4d6e9b10
              competencia: 2026-09-02
              discriminacao: Plano mensal - Período 02/09/2026 a 01/10/2026
              c_motivo: "99"
              x_motivo: Correção do valor do serviço prestado
              nfse_service_id: 8a2b7c1e-5d44-4f3a-b1a2-6c9d0e7f8a21
              valor: 109
      responses:
        "201":
          description: NFS-e substituta autorizada
          content:
            application/json:
              schema: *a39
        "202":
          description: NFS-e substituta enfileirada
          content:
            application/json:
              schema: *a39
        "401":
          description: Não autorizado
        "404":
          description: NFS-e original não encontrada
        "422":
          description: Nota original não pode ser substituída ou dados inválidos
  /v2/invoices/nfse/{id}/xml:
    get:
      tags:
        - NFS-e Arquivos
      summary: Baixar XML da NFS-e
      description: |
        Baixa o XML da NFS-e autorizada, como devolvido pela prefeitura ou pela SEFIN nacional.
        Retorna 404 enquanto a nota não tiver sido autorizada.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: XML da NFS-e
          content:
            application/xml:
              schema:
                type: string
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="nfse-3183.xml"
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada ou XML ainda não disponível
  /v2/invoices/nfse/{id}/pdf:
    get:
      tags:
        - NFS-e Arquivos
      summary: Baixar PDF (DANFS-e)
      description: |
        Baixa o DANFS-e em PDF, gerado a partir do XML autorizado.
        Só funciona depois da autorização. Antes disso retorna 404.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: PDF da NFS-e
          content:
            application/pdf:
              schema:
                type: string
                format: binary
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="nfse-3183.pdf"
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada ou ainda não autorizada
  /v2/invoices/nfse/{id}/send-email:
    post:
      tags:
        - NFS-e Arquivos
      summary: Enviar NFS-e por e-mail
      description: |
        Envia o PDF e o XML da NFS-e autorizada para os e-mails cadastrados no tomador.
        Não há campos de destinatário, assunto ou mensagem no payload.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFS-e autorizada (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: E-mail enviado
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: NFS-e 3183 enviada para fiscal@empresa.com.br.
                  recipientEmails:
                    type: array
                    items:
                      type: string
                      format: email
        "401":
          description: Não autorizado
        "404":
          description: NFS-e não encontrada
        "422":
          description: Nota não autorizada ou tomador sem e-mail
  /v2/invoices:
    post:
      tags:
        - NFCom
      summary: Criar NFCom
      description: |
        Cria uma NFCom usando destinatário e serviços **já cadastrados** (`client.id` e `items[].id`).

        Na maioria das integrações, prefira `POST /v2/invoices/nfcom/full`, que cadastra
        destinatário e serviços automaticamente.

        Campos principais: `model`, `issueDate`, `issueFinality`, `client`, `items`,
        `billingInfo`, `autoTransmit`, `emailNotificationAttachments`.

        ### Pré-requisitos
        - Cliente cadastrado com `client.id` válido
        - Serviços cadastrados com `items[].id` válido
        - Esta rota **não** cria cliente nem serviço automaticamente

        Webhook: configure a URL padrão no painel (este endpoint não aceita `notification_url` no body).
      requestBody:
        required: true
        content:
          application/json:
            schema: &a43
              type: object
              required:
                - model
                - issueDate
                - issueFinality
                - client
                - items
              properties:
                model:
                  type: integer
                  example: 62
                  description: Modelo da NF (62 = NFCom)
                issueDate:
                  type: string
                  example: 2024-08-21T10:30:00.000Z
                  description: |
                    Data de emissão. Aceita ISO, `YYYY-MM-DD` ou `DD/MM/YYYY`.
                    Não pode ser futura nem anterior a 5 dias.
                series:
                  type: string
                  pattern: ^\d+$
                  example: "1"
                  description: Série (opcional; se omitida, usa a das Configurações)
                issueFinality:
                  type: integer
                  enum:
                    - 0
                    - 3
                    - 4
                  example: 0
                  description: 0=Normal, 3=Substituição, 4=Ajuste
                prepaidServiceIndicator:
                  type: integer
                  enum:
                    - 0
                    - 1
                  default: 0
                networkMediaSessionIndicator:
                  type: integer
                  enum:
                    - 0
                    - 1
                  default: 0
                referenceModel:
                  type: integer
                  nullable: true
                  enum:
                    - 21
                    - 22
                    - 62
                  description: Obrigatório quando issueFinality = 3
                substituteReason:
                  type: integer
                  nullable: true
                  enum:
                    - 1
                    - 2
                    - 3
                    - 4
                    - 5
                  description: Obrigatório quando issueFinality = 3
                referenceMonthYear:
                  type: string
                  example: 08/2024
                  description: Formato MM/YYYY (obrigatório para referência modelo 21/22)
                referenceSeries:
                  type: string
                  maxLength: 3
                referenceNumber:
                  type: integer
                  nullable: true
                originalAccessKey:
                  type: string
                  minLength: 44
                  maxLength: 44
                  description: Obrigatório quando referenceModel = 62
                hashConvention115:
                  type: string
                  maxLength: 32
                crt:
                  type: string
                observation:
                  type: string
                  maxLength: 2000
                client:
                  type: object
                  required:
                    - id
                    - name
                    - personType
                    - document
                    - address
                    - number
                    - neighborhood
                    - uf
                    - subscriberType
                    - zipCode
                    - cityCode
                  properties:
                    id:
                      type: string
                      format: uuid
                      description: ID do cliente já cadastrado
                    name:
                      type: string
                    code:
                      type: string
                      maxLength: 15
                    email:
                      type: string
                      format: email
                    personType:
                      type: string
                      enum:
                        - PF
                        - PJ
                    abroad:
                      type: boolean
                      default: false
                    indicatorIe:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 9
                    ie:
                      type: string
                    im:
                      type: string
                    document:
                      type: string
                      description: CPF/CNPJ (BR) ou documento estrangeiro (2–20 chars)
                    phone:
                      type: string
                    address:
                      type: string
                      description: Logradouro
                    number:
                      type: string
                    neighborhood:
                      type: string
                    complement:
                      type: string
                    uf:
                      type: string
                      minLength: 2
                      maxLength: 2
                    subscriberType:
                      type: integer
                    usageType:
                      type: integer
                      enum:
                        - 1
                        - 2
                        - 3
                        - 4
                        - 5
                        - 6
                        - 7
                      default: 7
                    zipCode:
                      type: string
                    cityCode:
                      oneOf:
                        - type: string
                        - type: integer
                    countryCode:
                      type: integer
                      nullable: true
                      description: Obrigatório se abroad = true
                    countryName:
                      type: string
                      nullable: true
                      description: Obrigatório se abroad = true
                    contractNumber:
                      type: string
                      maxLength: 20
                    contractStartDate:
                      type: string
                      format: date-time
                      nullable: true
                    contractEndDate:
                      type: string
                      format: date-time
                      nullable: true
                items:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - id
                      - number
                      - code
                      - description
                      - classification
                      - unity
                      - quantity
                      - price
                      - totalValue
                    properties:
                      item_number:
                        type: integer
                        minimum: 1
                      id:
                        type: string
                        format: uuid
                        description: ID do serviço já cadastrado
                      number:
                        type: integer
                        description: Número sequencial do item na nota
                      code:
                        type: string
                        maxLength: 60
                      description:
                        type: string
                        maxLength: 120
                      classification:
                        type: string
                      unity:
                        type: integer
                      quantity:
                        type: number
                        minimum: 0.0001
                      price:
                        type: number
                        minimum: 0
                      totalValue:
                        type: number
                        minimum: 0
                      offprice:
                        type: number
                        minimum: 0
                        default: 0
                      otherExpenses:
                        type: number
                        minimum: 0
                        default: 0
                      icmsCst:
                        type: string
                        nullable: true
                      cfop:
                        type: string
                        nullable: true
                      icmsRate:
                        type: number
                      bcReductionRate:
                        type: number
                      pisCst:
                        type: string
                        nullable: true
                      pisRate:
                        type: number
                      cofinsCst:
                        type: string
                        nullable: true
                      cofinsRate:
                        type: number
                      funttelRate:
                        type: number
                      fustRate:
                        type: number
                      withheldIRRFRate:
                        type: number
                      withheldCSLLRate:
                        type: number
                      withheldPISRate:
                        type: number
                      withheldCOFINSRate:
                        type: number
                      municipalAliquot:
                        type: number
                      stateAliquot:
                        type: number
                      federalAliquot:
                        type: number
                      icmsInterstateRate:
                        type: number
                        nullable: true
                      icmsFcpRate:
                        type: number
                      fiscalBenefitCode:
                        type: string
                      ld_operator_cnpj:
                        type: string
                billingInfo:
                  type: object
                  required:
                    - billingType
                  properties:
                    billingType:
                      type: integer
                      enum:
                        - 0
                        - 1
                        - 2
                      description: 0=Normal, 1=Centralizado, 2=Cofaturamento
                    competence:
                      type: string
                      pattern: ^\d{6}$
                      example: "202408"
                    dueDateInvoice:
                      type: string
                      example: 2024-09-21
                    usagePeriodStart:
                      type: string
                      example: 2024-08-01
                    usagePeriodEnd:
                      type: string
                      example: 2024-08-31
                    barcode:
                      type: string
                      maxLength: 54
                    pixUrl:
                      type: string
                      maxLength: 2000
                    bankCode:
                      type: string
                    branchCode:
                      type: string
                    bankSlip:
                      type: string
                    creditDebitCard:
                      type: string
                    otherMethods:
                      type: string
                    centralizedCompanyCnpj:
                      type: string
                    centralizedCompanyState:
                      type: string
                      minLength: 2
                      maxLength: 2
                    nfcomLocalKey:
                      type: string
                      minLength: 44
                      maxLength: 44
                    addressType:
                      type: string
                      enum:
                        - client
                        - none
                        - custom
                      default: none
                    correspondenceStreet:
                      type: string
                    correspondenceNumber:
                      type: string
                    correspondenceNeighborhood:
                      type: string
                    correspondenceCity:
                      type: string
                    correspondenceUf:
                      type: string
                    correspondenceZipCode:
                      type: string
                    correspondenceComplement:
                      type: string
                    correspondencePhone:
                      type: string
                    correspondenceEmail:
                      type: string
                      format: email
                autoTransmit:
                  type: boolean
                  default: true
                  description: Se true, enfileira a transmissão à SEFAZ
                getObservationSettings:
                  type: boolean
                  default: true
                emailNotificationAttachments:
                  type: array
                  items:
                    type: string
                    enum:
                      - danfe
                      - xml
                  description: Anexos do e-mail pós-autorização
            example:
              summary: Criação de NFCom com cliente e serviço pré-cadastrados
              value:
                model: 62
                issueDate: 2024-08-21T10:30:00.000Z
                issueFinality: 0
                prepaidServiceIndicator: 0
                networkMediaSessionIndicator: 0
                observation: Serviços de telecomunicações - Agosto/2024
                client:
                  id: 123e4567-e89b-12d3-a456-426614174000
                  name: Cliente Exemplo Ltda
                  personType: PJ
                  document: "12345678000199"
                  indicatorIe: 9
                  address: Rua das Flores
                  number: "100"
                  neighborhood: Centro
                  uf: SP
                  zipCode: "01001000"
                  cityCode: "3550308"
                  subscriberType: 1
                  usageType: 4
                items:
                  - id: 456f7890-a12b-34c5-d678-901234567890
                    number: 1
                    code: INTERNET-100
                    description: Internet banda larga 100Mbps
                    classification: "0401"
                    unity: 1
                    quantity: 1
                    price: 89.9
                    totalValue: 89.9
                    offprice: 0
                    otherExpenses: 0
                    icmsCst: "00"
                    cfop: "5307"
                    icmsRate: 18
                billingInfo:
                  billingType: 0
                  competence: "202408"
                  dueDateInvoice: 2024-09-21
                  usagePeriodStart: 2024-08-01
                  usagePeriodEnd: 2024-08-31
                autoTransmit: true
                emailNotificationAttachments:
                  - danfe
                  - xml
      responses:
        "201":
          description: NFCom criada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                    example: NFCom criada com sucesso
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 123e4567-e89b-12d3-a456-426614174000
                      number:
                        type: integer
                        example: 1
                      series:
                        type: string
                        example: "001"
                      model:
                        type: integer
                        example: 62
                      access_key:
                        type: string
                        example: "35240812345678000123620010000001231234567890"
                      status:
                        type: string
                        enum:
                          - DRAFT
                          - PENDING_SUBMISSION
                          - SUBMITTING
                          - SUBMITTED
                          - VALIDATED
                          - PENDING_CANCELLATION
                          - CANCELLING
                          - CANCELLED
                          - REPLACED
                          - SUBMISSION_ERROR
                          - CANCELLATION_ERROR
                        description: SUBMITTED = autorizada pela SEFAZ (status final de uma nota válida). SUBMISSION_ERROR = rejeitada ou com
                          erro no envio.
                        example: SUBMITTED
                      issue_date:
                        type: string
                        format: date-time
                        example: 2024-08-21T10:30:00.000Z
                      total_amount:
                        type: number
                        example: 86.9
                      total_taxes:
                        type: number
                        example: 23.67
                      customer:
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                            example: uuid-da-empresa
                          company_name:
                            type: string
                            example: Empresa LTDA
                      client:
                        type: object
                        properties:
                          id:
                            type: string
                            format: uuid
                            example: 123e4567-e89b-12d3-a456-426614174000
                          name:
                            type: string
                            example: João da Silva
                          document:
                            type: string
                            example: "12345678901"
                      external_reference:
                        type: string
                        example: NFCOM-2024-001
                      created_at:
                        type: string
                        format: date-time
                        example: 2024-08-21T10:30:00.000Z
                      updated_at:
                        type: string
                        format: date-time
                        example: 2024-08-21T10:30:00.000Z
        "400":
          description: Dados inválidos ou erro de validação
          content:
            application/json:
              schema: &a44
                type: object
                properties:
                  status:
                    type: string
                    example: error
                  message:
                    type: string
                    example: Mensagem de erro
                  data:
                    type: object
                    properties:
                      errors:
                        type: array
                        items:
                          type: object
                          properties:
                            field:
                              type: string
                              example: campo_com_erro
                            message:
                              type: string
                              example: Descrição do erro específico
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: &a45
                type: object
                properties:
                  status:
                    type: string
                    example: error
                  message:
                    type: string
                    example: Token inválido ou expirado
  /v2/invoices/{id}:
    put:
      tags:
        - NFCom
      summary: Atualizar NFCom
      description: |
        Atualiza uma NFCom existente usando a API simplificada v2.

        ### ⚠️ **ATENÇÃO: PRÉ-REQUISITOS OBRIGATÓRIOS**
        Assim como na criação, esta API requer **dados pré-cadastrados**:
        - ✅ **Cliente** (`client.id`) deve existir no sistema
        - ✅ **Serviços/produtos** (`items[].id`) devem estar cadastrados
        - ✅ Todos os **códigos internos** devem referenciar registros válidos

        ### ⚠️ Limitações de Atualização:
        - Só é possível atualizar NFCom em status **DRAFT** ou **SUBMISSION_ERROR**
        - A atualização **substitui todos os dados** da nota
        - Requer os **mesmos campos obrigatórios** da criação
        - **Não altera dados** de clientes/produtos existentes

        ### 🔗 **Notificações por Webhook (Opcional)**

        ⚠️ **ATUALIZAÇÃO DE WEBHOOK**: Você pode alterar a URL de webhook durante a atualização:

        #### **Opção 1: Nova URL Específica (PRIORIDADE MÁXIMA)**
        ```json
        {
          "notification_url": "https://novo-sistema.com/webhook/nfcom",
          "client_id": "...",
          "items": [...]
        }
        ```

        #### **Opção 2: Remover URL Específica**
        - Omita `notification_url` para usar URL padrão do sistema
        - Ou configure `notification_url: null` para remover completamente

        📚 **Documentação**: [Guia de Implementação de Webhooks](./WEBHOOK-IMPLEMENTATION-GUIDE.md)

        ### 🎯 Para Desenvolvedores:
        - **Use para**: Corrigir dados antes da transmissão à SEFAZ
        - **Use para**: Corrigir NFCom rejeitadas pela SEFAZ
        - **Importante**: Mantenha os mesmos IDs de referência dos dados originais
      requestBody:
        required: true
        content:
          application/json:
            schema: *a43
            example:
              summary: Atualização de NFCom (mesmo contrato da criação)
              value:
                model: 62
                issueDate: 2024-08-21T14:30:00.000Z
                issueFinality: 0
                observation: Serviços de telecomunicações - Agosto/2024 - Corrigido
                client:
                  id: 123e4567-e89b-12d3-a456-426614174000
                  name: Cliente Exemplo Ltda
                  personType: PJ
                  document: "12345678000199"
                  indicatorIe: 9
                  address: Rua das Flores
                  number: "100"
                  neighborhood: Centro
                  uf: SP
                  zipCode: "01001000"
                  cityCode: "3550308"
                  subscriberType: 1
                  usageType: 4
                items:
                  - id: 456f7890-a12b-34c5-d678-901234567890
                    number: 1
                    code: INTERNET-100
                    description: Internet banda larga 100Mbps
                    classification: "0401"
                    unity: 1
                    quantity: 1
                    price: 99.9
                    totalValue: 99.9
                billingInfo:
                  billingType: 0
                  competence: "202408"
                  dueDateInvoice: 2024-09-25
                  usagePeriodStart: 2024-08-01
                  usagePeriodEnd: 2024-08-31
                autoTransmit: true
      responses:
        "200":
          description: NFCom atualizada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                    example: NFCom atualizada com sucesso
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: 123e4567-e89b-12d3-a456-426614174000
                      number:
                        type: integer
                        example: 1
                      series:
                        type: string
                        example: "001"
                      status:
                        type: string
                        example: DRAFT
                      total_amount:
                        type: number
                        example: 89.9
                      external_reference:
                        type: string
                        example: NFCOM-2024-001-UPD
                      updated_at:
                        type: string
                        format: date-time
                        example: 2024-08-21T14:30:00.000Z
                      changes_summary:
                        type: object
                        properties:
                          fields_changed:
                            type: array
                            items:
                              type: string
                            example:
                              - external_reference
                              - items[0].price
                              - total_amount
                          previous_total:
                            type: number
                            example: 86.9
                          new_total:
                            type: number
                            example: 89.9
        "400":
          description: Dados inválidos ou NFCom não pode ser atualizada
          content:
            application/json:
              schema: *a44
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: *a45
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
    delete:
      tags:
        - NFCom
      summary: Excluir NFCom (soft delete)
      description: |
        Exclui logicamente uma NFCom. Somente notas que **ainda não foram autorizadas**
        pela SEFAZ podem ser excluídas (ex.: `DRAFT`, `SUBMISSION_ERROR`).

        NFCom autorizadas (`SUBMITTED`) devem ser **canceladas** via
        `POST /v2/invoices/{id}/cancel`.
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                reason:
                  type: string
                  minLength: 10
                  maxLength: 500
                  description: Motivo da exclusão (opcional)
                  example: Duplicidade no envio do integrador
      responses:
        "200":
          description: NFCom excluída
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: NFCom excluída com sucesso
        "400":
          description: NFCom não pode ser excluída no status atual
          content:
            application/json:
              schema: *a44
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: *a45
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
    get:
      tags:
        - NFCom Consultas
      summary: Consultar NFCom por ID
      description: |
        Consulta uma NFCom específica pelo seu ID, retornando dados filtrados para segurança.

        ### 🔒 **Segurança e Privacidade de Dados**

        Esta API aplica **filtros de segurança** nos dados retornados:

        #### ✅ **Dados Expostos do Cliente (Customer)**:
        - `id`, `name`, `company` - Identificação básica
        - `document` (CPF/CNPJ), `ie` (Inscrição Estadual) - Dados fiscais necessários
        - `addresses` - Apenas `id`, `state`, `city`, `city_code` (para QR Code e localização)
      parameters:
        - name: id
          in: path
          required: true
          description: ID único da NFCom (UUID)
          schema:
            type: string
            format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
      responses:
        "200":
          description: NFCom encontrada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                    description: ID único da NFCom
                    example: 123e4567-e89b-12d3-a456-426614174000
                  number:
                    type: integer
                    description: Número da NFCom
                    example: 123
                  nfeKey:
                    type: string
                    nullable: true
                    description: Chave de acesso da NFCom (44 dígitos)
                    example: "35240514200166000187620010000001231234567890"
                  environment:
                    type: integer
                    description: Ambiente de emissão (1=Homologação, 2=Produção)
                    enum:
                      - 1
                      - 2
                    example: 2
                  externalReference:
                    type: string
                    nullable: true
                    description: Referência externa da NFCom
                    example: REF-2024-001
                  status:
                    type: string
                    description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                      retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a SEFAZ).
                      Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais; PENDING_SUBMISSION na
                      fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada ou com erro no envio;
                      PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED cancelada;
                      CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED substituída por
                      outra NFCom."
                    enum:
                      - DRAFT
                      - PENDING_SUBMISSION
                      - SUBMITTING
                      - SUBMITTED
                      - PENDING_CANCELLATION
                      - CANCELLING
                      - CANCELLED
                      - SUBMISSION_ERROR
                      - CANCELLATION_ERROR
                      - VALIDATED
                    example: SUBMITTED
                  issueDate:
                    type: string
                    format: date-time
                    description: Data de emissão da NFCom
                    example: 2024-08-15T10:30:00.000Z
                  model:
                    type: integer
                    description: Modelo da nota fiscal
                    example: 62
                  series:
                    type: string
                    description: Série da NFCom
                    example: "001"
                  totalValue:
                    type: number
                    format: decimal
                    nullable: true
                    description: Valor total da NFCom
                    example: 150.75
                  qrCode:
                    type: string
                    nullable: true
                    description: Código QR da NFCom (URL para consulta)
                    example: https://dfe-portal.svrs.rs.gov.br/nfcom/qrCode?chNFCom=35240514200166000187620010000001231234567890&tpAmb=2
                  client:
                    type: object
                    description: Dados do destinatário da NFCom
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: ID do cliente
                        example: client-uuid-123
                      name:
                        type: string
                        description: Nome do cliente
                        example: João da Silva
                      document:
                        type: string
                        description: CPF ou CNPJ do cliente
                        example: "12345678901"
                      email:
                        type: string
                        format: email
                        nullable: true
                        description: Email do cliente
                        example: joao@email.com
                      cityName:
                        type: string
                        description: Nome da cidade do cliente
                        example: São Paulo
                    required:
                      - id
                      - name
                      - document
                  customer:
                    type: object
                    description: Dados filtrados da empresa emissora (dados fiscais necessários inclusos)
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: ID da empresa
                        example: customer-uuid-456
                      name:
                        type: string
                        description: Nome da empresa
                        example: Empresa Telecomunicações LTDA
                      company:
                        type: string
                        description: Razão social da empresa
                        example: Empresa Telecomunicações LTDA
                      document:
                        type: string
                        description: CNPJ da empresa
                        example: "12345678000199"
                      ie:
                        type: string
                        description: Inscrição Estadual da empresa
                        example: "123456789"
                      addresses:
                        type: array
                        description: Endereços da empresa (dados não sensíveis)
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              format: uuid
                              description: ID do endereço
                              example: address-uuid-789
                            state:
                              type: string
                              description: Estado (UF)
                              example: SP
                            city:
                              type: string
                              description: Cidade
                              example: São Paulo
                            city_code:
                              type: string
                              description: Código da cidade (IBGE)
                              example: "3550308"
                          required:
                            - id
                            - state
                            - city
                            - city_code
                    required:
                      - id
                      - name
                      - company
                      - document
                      - ie
                      - addresses
                  services:
                    type: array
                    description: Lista de serviços da NFCom
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: ID do serviço
                        description:
                          type: string
                          description: Descrição do serviço
                        quantity:
                          type: number
                          description: Quantidade
                        unitValue:
                          type: number
                          format: decimal
                          description: Valor unitário
                        totalValue:
                          type: number
                          format: decimal
                          description: Valor total
                  lastEvent:
                    type: object
                    nullable: true
                    description: Último evento da NFCom
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: ID do evento
                      type:
                        type: string
                        description: Tipo do evento
                        example: AUTHORIZATION
                      description:
                        type: string
                        description: Descrição do evento
                        example: Nota fiscal autorizada com sucesso
                      date:
                        type: string
                        format: date-time
                        description: Data do evento
                        example: 2024-08-15T10:35:00.000Z
                  billingInfo:
                    type: object
                    nullable: true
                    description: Informações de faturamento da NFCom
                    properties:
                      billingType:
                        type: integer
                        description: Tipo de faturamento (0=Normal, 1=Centralizado, 2=Cofaturamento)
                        enum:
                          - 0
                          - 1
                          - 2
                        example: 0
                      competence:
                        type: string
                        nullable: true
                        description: Competência do faturamento (YYYYMM)
                        example: "202408"
                      dueDateInvoice:
                        type: string
                        format: date
                        nullable: true
                        description: Data de vencimento
                        example: 2024-09-15
                  logo:
                    type: string
                    description: URL assinada para acesso à logo da empresa
                    example: https://storage.telcomnfe.com.br/logos/signed-url-here
                  created_at:
                    type: string
                    format: date-time
                    description: Data de criação da NFCom
                    example: 2024-08-15T10:30:00.000Z
                  updated_at:
                    type: string
                    format: date-time
                    description: Data da última atualização
                    example: 2024-08-15T10:35:00.000Z
                required:
                  - id
                  - environment
                  - status
                  - issueDate
                  - model
                  - series
                  - client
                  - customer
                  - services
                  - logo
                  - created_at
                  - updated_at
              examples:
                invoice_show_example:
                  summary: Exemplo de NFCom Completa
                  value:
                    id: 123e4567-e89b-12d3-a456-426614174000
                    number: 123
                    nfeKey: "35240514200166000187620010000001231234567890"
                    environment: 2
                    externalReference: REF-2024-001
                    status: SUBMITTED
                    issueDate: 2024-08-15T10:30:00.000Z
                    model: 62
                    series: "001"
                    totalValue: 150.75
                    qrCode: https://dfe-portal.svrs.rs.gov.br/nfcom/qrCode?chNFCom=35240514200166000187620010000001231234567890&tpAmb=2
                    client:
                      id: client-uuid-123
                      name: João da Silva
                      document: "12345678901"
                      email: joao@email.com
                      cityName: São Paulo
                    customer:
                      id: customer-uuid-456
                      name: Empresa Telecomunicações LTDA
                      company: Empresa Telecomunicações LTDA
                      document: "12345678000199"
                      ie: "123456789"
                      addresses:
                        - id: address-uuid-789
                          state: SP
                          city: São Paulo
                          city_code: "3550308"
                    services:
                      - id: service-uuid-001
                        description: Internet Banda Larga
                        quantity: 1
                        price: 99.9
                        totalValue: 99.9
                    lastEvent:
                      type: SUBMISSION
                      description: Nota fiscal enviada e autorizada com sucesso
                      date: 2024-08-15T10:35:00.000Z
                    billingInfo:
                      billingType: 0
                      competence: "202408"
                    logo: https://r2-storage.telcomnfe.com.br/signed-url
                    created_at: 2024-08-15T10:30:00.000Z
                    updated_at: 2024-08-15T10:35:00.000Z
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: *a45
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
              example:
                status: error
                message: Nota Fiscal Não Encontrada.
                error: NOT_FOUND
  /v2/invoices/{id}/cancel:
    post:
      tags:
        - NFCom
      summary: Cancelar NFCom
      description: |
        Cancela uma NFCom já transmitida e autorizada pela SEFAZ.

        ### ⚠️ **Limitações:**
        - Só cancela NFCom com status **SUBMITTED** (autorizada pela SEFAZ)
        - **Prazo**: até o **5º dia do mês seguinte** à data de emissão (23:59:59)
        - **Irreversível**: o cancelamento não pode ser desfeito
        - **Justificativa**: campo `reason` obrigatório (recomendado ≥ 15 caracteres; lote exige mínimo 15)

        ### 🎯 **Para Desenvolvedores:**
        - Sempre informe motivo claro e detalhado
        - Verifique status antes de tentar cancelar
        - Processe resposta para atualizar interface
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
                  example: Cancelamento solicitado pelo cliente devido a erro na cobrança
                  description: |
                    Motivo do cancelamento (obrigatório).
                    Em `POST /v2/invoices/{id}/cancel` não há mínimo no Joi; recomendado ≥ 15 caracteres.
                    Em cancelamento em lote (`bulk-cancel`) o mínimo é 15.
            example:
              summary: Exemplo de cancelamento de NFCom
              value:
                reason: Cancelamento solicitado pelo cliente devido a erro na cobrança
      responses:
        "200":
          description: NFCom cancelada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                    example: NFCom cancelada com sucesso
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                        example: b8e3d1a2-4c5f-6789-abcd-ef1234567890
                      status:
                        type: string
                        example: CANCELLED
                      cancelDate:
                        type: string
                        format: date-time
                        example: 2024-01-15T14:30:00Z
                      cancelReason:
                        type: string
                        example: Cancelamento solicitado pelo cliente devido a erro na cobrança
        "400":
          description: Não foi possível cancelar a NFCom
          content:
            application/json:
              schema: *a44
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
  /v2/invoices/list:
    get:
      tags:
        - NFCom Consultas
      summary: Listar NFCom
      description: |
        Lista as NFCom da empresa autenticada com suporte a **paginação**, **ordenação** e **filtros**.

        ### 📋 Resposta

        Retorna um objeto com:
        - `invoices` — array com os dados essenciais de cada NFCom da página solicitada
        - `count` — total de registros encontrados (use para calcular o número de páginas)

        ### 🔍 Filtros disponíveis (`filters`)

        Os filtros são passados como parâmetros aninhados no formato `filters[campo]=valor`:

        | Filtro | Tipo | Descrição |
        |---|---|---|
        | `filters[startDate]` | `string (date)` | Data de emissão inicial (ISO 8601) |
        | `filters[endDate]` | `string (date)` | Data de emissão final (ISO 8601) — inclui o dia inteiro até 23:59:59 |
        | `filters[startNumber]` | `integer` | Número inicial para filtro por intervalo |
        | `filters[endNumber]` | `integer` | Número final para filtro por intervalo |
        | `filters[name]` | `string` | Busca parcial (case-insensitive) pelo nome do destinatário |
        | `filters[document]` | `string` | Busca parcial pelo CPF/CNPJ do destinatário (aceita formatado ou só números) |
        | `filters[status]` | `string \| string[]` | Status da NFCom — pode ser um valor único ou array de valores |

        **Exemplo de filtro por período e status:**
        ```
        GET /v2/invoices/list?filters[startDate]=2024-08-01&filters[endDate]=2024-08-31&filters[status][]=SUBMITTED&filters[status][]=VALIDATED
        ```

        **Exemplo de filtro por destinatário:**
        ```
        GET /v2/invoices/list?filters[name]=João&filters[document]=12345678901
        ```

        O filtro por faixa (`startNumber` + `endNumber`) inclui as duas pontas. Os números devem ser inteiros
        (vazio, decimal ou não numérico volta com 400). Status fora da lista abaixo volta com 400 e a mensagem lista os status válidos.

        ### 📊 Campos de Ordenação (`sortField`)

        Sem `sortField`, a ordem padrão é **data de atualização decrescente (`updatedAt DESC`) com o `id` decrescente
        como desempate**, a mesma para qualquer `rowsPerPage`. Com `sortField`, o `id` decrescente também é usado
        como desempate, então a paginação é estável. Campo fora da lista volta com 400.

        | Valor | Descrição |
        |---|---|
        | `updatedAt` | Data de atualização *(padrão, decrescente)* |
        | `createdAt` | Data de criação |
        | `issueDate` | Data de emissão |
        | `number` | Número da NFCom |
        | `totalAmount` | Valor total |
        | `status` | Status |
        | `client.name` | Nome do destinatário |
        | `client.document` | CPF/CNPJ do destinatário |

        ### 📦 Detalhes completos (`full_details`)

        Por padrão, a listagem retorna apenas os **campos essenciais** de cada NFCom para melhor performance.
        Passe `full_details=true` para incluir todos os campos da entidade (dados de faturamento, último evento completo, etc.).
      parameters:
        - name: page
          in: query
          required: false
          description: |
            Índice da página **baseado em 0** (`page=0` = primeira página, `page=1` = segunda; `page=1` não mudou).
            Cálculo interno: `skip = page * rowsPerPage`. Valor negativo, decimal ou não numérico volta com 400.

            **Mudança (correção):** `page` omitido agora traz a primeira página. Antes o backend usava `1` e pulava
            `rowsPerPage` registros — por isso uma chamada sem `page` e com `rowsPerPage` grande (ou um filtro com
            poucas notas) vinha com `count` e lista vazia.
          schema:
            type: integer
            minimum: 0
            default: 0
          example: 0
        - name: rowsPerPage
          in: query
          required: false
          description: |
            Quantidade de itens por página, sem limite máximo. `0` traz todos os registros; omitido ou vazio usa 10.
            Negativo ou não numérico volta com 400.
          schema:
            type: number
            minimum: 0
            default: 10
          example: 10
        - name: sortField
          in: query
          required: false
          description: Campo utilizado para ordenação dos resultados
          schema:
            type: string
            enum:
              - createdAt
              - updatedAt
              - issueDate
              - number
              - series
              - externalReference
              - issueFinality
              - totalAmount
              - status
              - client.name
              - client.document
            default: updatedAt
          example: issueDate
        - name: sortDirection
          in: query
          required: false
          description: Direção da ordenação quando `sortField` é informado (aceita maiúsculas ou minúsculas). Sem `sortField`, a
            ordem é `updatedAt DESC`.
          schema:
            type: string
            enum:
              - ASC
              - DESC
            default: ASC
          example: DESC
        - name: full_details
          in: query
          required: false
          description: |
            Quando `true`, retorna todos os campos da NFCom incluindo dados de faturamento e
            último evento completo. Por padrão retorna apenas campos essenciais para melhor performance.
          schema:
            type: string
            enum:
              - "true"
              - "false"
            default: "false"
          example: "false"
        - name: filters[startDate]
          in: query
          required: false
          description: Data de emissão inicial (filtro de período)
          schema:
            type: string
            format: date
          example: 2024-08-01
        - name: filters[endDate]
          in: query
          required: false
          description: Data de emissão final (filtro de período — inclui até 23:59:59 do dia)
          schema:
            type: string
            format: date
          example: 2024-08-31
        - name: filters[startNumber]
          in: query
          required: false
          description: Número inicial da NFCom (filtro por intervalo de números)
          schema:
            type: integer
          example: 100
        - name: filters[endNumber]
          in: query
          required: false
          description: Número final da NFCom (filtro por intervalo de números)
          schema:
            type: integer
          example: 200
        - name: filters[name]
          in: query
          required: false
          description: Busca parcial (case-insensitive) pelo nome do destinatário da NFCom
          schema:
            type: string
          example: João
        - name: filters[document]
          in: query
          required: false
          description: |
            Busca parcial pelo CPF ou CNPJ do destinatário.
            Aceita tanto valor formatado (`123.456.789-01`) quanto sem formatação (`12345678901`).
          schema:
            type: string
          example: "12345678901"
        - name: filters[status][]
          in: query
          required: false
          description: |
            Filtra por um ou mais status. Para múltiplos status, repita o parâmetro:
            `filters[status][]=SUBMITTED&filters[status][]=VALIDATED`
          schema:
            type: array
            items:
              type: string
              enum:
                - DRAFT
                - PENDING_SUBMISSION
                - SUBMITTING
                - SUBMITTED
                - PENDING_CANCELLATION
                - CANCELLING
                - CANCELLED
                - REPLACED
                - SUBMISSION_ERROR
                - CANCELLATION_ERROR
                - VALIDATED
          example:
            - SUBMITTED
            - VALIDATED
      responses:
        "200":
          description: Lista de NFCom retornada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  invoices:
                    type: array
                    description: Lista de NFCom retornadas
                    items:
                      type: object
                      description: |
                        Dados essenciais de cada NFCom na listagem.
                        Quando `full_details=true`, campos adicionais da entidade completa são incluídos.
                      properties:
                        id:
                          type: string
                          format: uuid
                          description: ID único da NFCom
                          example: 123e4567-e89b-12d3-a456-426614174000
                        externalReference:
                          type: string
                          nullable: true
                          description: Referência externa da NFCom (código do ERP ou sistema integrador)
                          example: NFCOM-2024-001
                        number:
                          type: integer
                          description: Número sequencial da NFCom
                          example: 1234
                        series:
                          type: string
                          description: Série da NFCom
                          example: "001"
                        issueDate:
                          type: string
                          format: date-time
                          description: Data de emissão da NFCom
                          example: 2024-08-15T10:30:00.000Z
                        issueFinality:
                          type: string
                          description: Finalidade de emissão (1=Normal, 2=Complementar, 3=Ajuste, 4=Devolução)
                          enum:
                            - "1"
                            - "2"
                            - "3"
                            - "4"
                          example: "1"
                        totalAmount:
                          type: number
                          format: decimal
                          description: Valor total da NFCom
                          example: 150.75
                        status:
                          type: string
                          description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                            retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a
                            SEFAZ). Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais;
                            PENDING_SUBMISSION na fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada
                            ou com erro no envio; PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED
                            cancelada; CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED
                            substituída por outra NFCom."
                          enum:
                            - DRAFT
                            - PENDING_SUBMISSION
                            - SUBMITTING
                            - SUBMITTED
                            - PENDING_CANCELLATION
                            - CANCELLING
                            - CANCELLED
                            - REPLACED
                            - SUBMISSION_ERROR
                            - CANCELLATION_ERROR
                            - VALIDATED
                          example: SUBMITTED
                        statusDescription:
                          type: string
                          description: Descrição legível do status com mensagem do último evento e protocolo
                          example: Autorizado o uso da NF-e - 135240823456789012345 - 15/08/2024 10:30:00
                        client:
                          type: object
                          description: Dados resumidos do destinatário
                          properties:
                            name:
                              type: string
                              description: Nome/razão social do destinatário
                              example: João da Silva
                            document:
                              type: string
                              description: CPF ou CNPJ do destinatário
                              example: "12345678901"
                            abroad:
                              type: boolean
                              description: Indica se o destinatário é estrangeiro
                              example: false
                        emailSendingInfo:
                          type: object
                          description: Informações sobre o histórico de envio por email desta NFCom
                          properties:
                            hasEmailLogs:
                              type: boolean
                              description: Indica se há histórico de envio de email para esta NFCom
                              example: true
                            lastEmailSent:
                              type: string
                              format: date-time
                              nullable: true
                              description: Data/hora do último envio de email (ISO 8601)
                              example: 2024-08-15T11:00:00.000Z
                            recipientEmails:
                              type: array
                              description: Lista de emails para os quais foi enviado no último envio
                              items:
                                type: string
                                format: email
                              example:
                                - joao@email.com
                                - financeiro@empresa.com
                            lastSendStatus:
                              type: string
                              nullable: true
                              description: Status geral do último envio por email
                              enum:
                                - SUCCESS
                                - FAILED
                                - PARTIAL
                              example: SUCCESS
                            lastSentFiles:
                              type: object
                              description: Arquivos enviados no último envio por email
                              properties:
                                xml:
                                  type: boolean
                                  description: Se o XML foi solicitado no último envio
                                  example: true
                                pdf:
                                  type: boolean
                                  description: Se o PDF foi solicitado no último envio
                                  example: true
                                xmlSuccess:
                                  type: boolean
                                  description: Se o XML foi enviado com sucesso
                                  example: true
                                pdfSuccess:
                                  type: boolean
                                  description: Se o PDF foi enviado com sucesso
                                  example: true
                  count:
                    type: integer
                    description: Total de registros encontrados (para paginação)
                    example: 42
              example:
                invoices:
                  - id: 123e4567-e89b-12d3-a456-426614174000
                    externalReference: NFCOM-2024-001
                    number: 1234
                    series: "001"
                    issueDate: 2024-08-15T10:30:00.000Z
                    issueFinality: "1"
                    totalAmount: 150.75
                    status: SUBMITTED
                    statusDescription: Autorizado o uso da NF-e - 135240823456789012345 - 15/08/2024 10:30:00
                    client:
                      name: João da Silva
                      document: "12345678901"
                      abroad: false
                    emailSendingInfo:
                      hasEmailLogs: true
                      lastEmailSent: 2024-08-15T11:00:00.000Z
                      recipientEmails:
                        - joao@email.com
                      lastSendStatus: SUCCESS
                      lastSentFiles:
                        xml: true
                        pdf: true
                        xmlSuccess: true
                        pdfSuccess: true
                  - id: 987fcdeb-51a2-43d7-b891-123456789abc
                    externalReference: null
                    number: 1235
                    series: "001"
                    issueDate: 2024-08-16T09:00:00.000Z
                    issueFinality: "1"
                    totalAmount: 89.9
                    status: DRAFT
                    statusDescription: ""
                    client:
                      name: Maria Aparecida
                      document: "98765432100"
                      abroad: false
                    emailSendingInfo:
                      hasEmailLogs: false
                      recipientEmails: []
                      lastSentFiles:
                        xml: false
                        pdf: false
                        xmlSuccess: false
                        pdfSuccess: false
                count: 42
        "400":
          description: Parâmetro inválido (page, rowsPerPage, sortField, sortDirection, status ou número da faixa)
          content:
            application/json:
              schema: *a44
              example:
                status: error
                message: "Status inválido no filtro: NAOEXISTE. Status válidos: DRAFT, PENDING_SUBMISSION, SUBMITTING, SUBMITTED,
                  PENDING_CANCELLATION, CANCELLING, CANCELLED, REPLACED, SUBMISSION_ERROR, CANCELLATION_ERROR,
                  VALIDATED."
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: *a45
        "500":
          description: Erro interno ao processar a listagem
          content:
            application/json:
              schema: *a44
  /v2/invoices/status:
    get:
      tags:
        - NFCom Consultas
      summary: Consultar Status de NFCom
      description: |
        Consulta o status de uma NFCom utilizando diferentes critérios de busca.

        ### 🔍 **Critérios de Busca Disponíveis**

        Você pode consultar o status usando **qualquer um** dos critérios abaixo:

        #### **Opção 1: Por ID da NFCom (UUID)**
        ```
        GET /v2/invoices/status?nfcomId=123e4567-e89b-12d3-a456-426614174000
        ```

        #### **Opção 2: Por Número + Série**
        ```
        GET /v2/invoices/status?number=123&series=001
        ```

        #### **Opção 3: Por Referência Externa**
        ```
        GET /v2/invoices/status?externalReference=REF-2024-001
        ```

        #### **Opção 4: Combinação de Critérios**
        ```
        GET /v2/invoices/status?number=123&series=001&model=62
        ```

        ### 📊 **Status Possíveis da NFCom**

        | Status | Descrição |
        |--------|-----------|
        | `PENDING_SUBMISSION` | Aguardando envio para a SEFAZ |
        | `SUBMITTING` | Enviando para a SEFAZ |
        | `SUBMITTED` | Enviada/Autorizada pela SEFAZ |
        | `PENDING_CANCELLATION` | Aguardando cancelamento na SEFAZ |
        | `CANCELLING` | Cancelando na SEFAZ |
        | `CANCELLED` | Cancelada |
        | `SUBMISSION_ERROR` | Erro no envio para a SEFAZ |
        | `CANCELLATION_ERROR` | Erro no cancelamento na SEFAZ |

        ### 🎯 **Casos de Uso**:
        - Monitoramento de status em tempo real
        - Verificação antes de operações (cancelamento, etc.)
        - Sincronização com sistemas externos
        - Validação de integrações

        ### ⚠️ **Observações Importantes**:
        - Pelo menos **um parâmetro** deve ser informado
        - A busca é **case-sensitive** para strings
        - `series` deve ser numérica (máximo 3 dígitos)
        - `model` atualmente suporta apenas o valor `62` (NFCom)
      parameters:
        - name: nfcomId
          in: query
          required: false
          description: ID único da NFCom (UUID)
          schema:
            type: string
            format: uuid
          example: 123e4567-e89b-12d3-a456-426614174000
        - name: number
          in: query
          required: false
          description: Número da NFCom
          schema:
            type: integer
            minimum: 1
          example: 123
        - name: series
          in: query
          required: false
          description: Série da NFCom (máximo 3 dígitos)
          schema:
            type: string
            pattern: ^\d+$
            maxLength: 3
          example: "001"
        - name: model
          in: query
          required: false
          description: Modelo da nota fiscal (apenas 62 para NFCom)
          schema:
            type: integer
            enum:
              - 62
          example: 62
        - name: externalReference
          in: query
          required: false
          description: Referência externa da NFCom
          schema:
            type: string
            maxLength: 255
          example: REF-2024-001
      responses:
        "200":
          description: Status da NFCom consultado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  nfcom:
                    type: object
                    description: Dados da NFCom consultada
                    properties:
                      id:
                        type: string
                        format: uuid
                        description: ID único da NFCom
                        example: 6c6ba808-19d6-40f3-b72d-eed3c4e11d67
                      number:
                        type: integer
                        description: Número da NFCom
                        example: 68
                      series:
                        type: string
                        description: Série da NFCom
                        example: "3"
                      model:
                        type: integer
                        description: Modelo da nota fiscal
                        example: 62
                      status:
                        type: string
                        description: "Status da NFCom. SUBMITTED = autorizada pela SEFAZ (é o status final de uma nota válida, gravado no
                          retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda aguarda a
                          SEFAZ). Demais: DRAFT rascunho; VALIDATED legado, não é gravado nas emissões atuais;
                          PENDING_SUBMISSION na fila de envio; SUBMITTING em envio à SEFAZ; SUBMISSION_ERROR rejeitada
                          ou com erro no envio; PENDING_CANCELLATION e CANCELLING cancelamento em andamento; CANCELLED
                          cancelada; CANCELLATION_ERROR cancelamento recusado (a nota continua autorizada); REPLACED
                          substituída por outra NFCom."
                        enum:
                          - DRAFT
                          - PENDING_SUBMISSION
                          - SUBMITTING
                          - SUBMITTED
                          - PENDING_CANCELLATION
                          - CANCELLING
                          - CANCELLED
                          - SUBMISSION_ERROR
                          - CANCELLATION_ERROR
                          - VALIDATED
                        example: SUBMITTED
                      nfcom_key:
                        type: string
                        nullable: true
                        description: Chave de acesso da NFCom (44 dígitos, disponível após autorização)
                        example: "15250917055961000104620030000000681020352394"
                      protocol_number:
                        type: string
                        nullable: true
                        description: Número do protocolo da SEFAZ (disponível após autorização)
                        example: "3152500007805358"
                      environment:
                        type: string
                        description: Ambiente de emissão
                        enum:
                          - homologacao
                          - producao
                        example: homologacao
                      issue_date:
                        type: string
                        format: date-time
                        description: Data de emissão da NFCom
                        example: 2025-09-05T03:00:00.000Z
                      created_at:
                        type: string
                        format: date-time
                        description: Data de criação da NFCom no sistema
                        example: 2025-09-09T18:08:18.611Z
                      updated_at:
                        type: string
                        format: date-time
                        description: Data da última atualização da NFCom
                        example: 2025-09-09T18:08:25.204Z
                      client:
                        type: object
                        description: Dados do destinatário da NFCom
                        properties:
                          name:
                            type: string
                            description: Nome do cliente
                            example: Kauê Henry Ferreira
                          document:
                            type: string
                            description: CPF ou CNPJ do cliente
                            example: "88061827816"
                          email:
                            type: string
                            format: email
                            description: Email do cliente
                            example: geison180@gmail.com
                        required:
                          - name
                          - document
                          - email
                      documents:
                        type: object
                        description: URLs para download dos documentos da NFCom
                        properties:
                          xml_url:
                            type: string
                            nullable: true
                            description: URL para download do XML da NFCom
                            example: https://api.nfcom.telcomnfe.com.br/v2/invoices/6c6ba808-19d6-40f3-b72d-eed3c4e11d67/documents/xml
                          pdf_url:
                            type: string
                            nullable: true
                            description: URL para download do PDF da NFCom
                            example: https://api.nfcom.telcomnfe.com.br/v2/invoices/6c6ba808-19d6-40f3-b72d-eed3c4e11d67/documents/pdf
                        required:
                          - xml_url
                          - pdf_url
                    required:
                      - id
                      - number
                      - series
                      - model
                      - status
                      - environment
                      - issue_date
                      - created_at
                      - updated_at
                      - client
                      - documents
                required:
                  - nfcom:
                      lastEvent:
                        type: object
                        nullable: true
                        description: Último evento registrado para a NFCom
                        properties:
                          type:
                            type: string
                            description: Tipo do evento
                            enum:
                              - CREATION
                              - PENDING_SUBMISSION
                              - SUBMITTING
                              - SUBMISSION
                              - SUBMISSION_ERROR
                              - PENDING_CANCELLATION
                              - CANCELLING
                              - CANCELLATION
                              - CANCELLATION_ERROR
                              - VALIDATION
                            example: SUBMISSION
                          description:
                            type: string
                            description: Descrição detalhada do evento
                            example: Nota fiscal autorizada com sucesso
                          date:
                            type: string
                            format: date-time
                            description: Data e hora do evento
                            example: 2024-08-15T10:35:00.000Z
                          protocol:
                            type: string
                            nullable: true
                            description: Protocolo da SEFAZ (quando aplicável)
                            example: "135240000123456"
                        required:
                          - type
                          - description
                          - date
                    required:
                      - id
                      - number
                      - series
                      - model
                      - status
                      - issueDate
                      - customer
                      - client
              examples:
                submitted_status:
                  summary: NFCom Enviada/Autorizada
                  value:
                    nfcom:
                      id: 6c6ba808-19d6-40f3-b72d-eed3c4e11d67
                      number: 68
                      series: "3"
                      model: 62
                      status: SUBMITTED
                      nfcom_key: "15250917055961000104620030000000681020352394"
                      protocol_number: "3152500007805358"
                      environment: homologacao
                      issue_date: 2025-09-05T03:00:00.000Z
                      created_at: 2025-09-09T18:08:18.611Z
                      updated_at: 2025-09-09T18:08:25.204Z
                      client:
                        name: Kauê Henry Ferreira
                        document: "88061827816"
                        email: geison180@gmail.com
                      documents:
                        xml_url: https://api.nfcom.telcomnfe.com.br/v2/invoices/6c6ba808-19d6-40f3-b72d-eed3c4e11d67/documents/xml
                        pdf_url: https://api.nfcom.telcomnfe.com.br/v2/invoices/6c6ba808-19d6-40f3-b72d-eed3c4e11d67/documents/pdf
                submission_error_status:
                  summary: NFCom com Erro de Envio
                  value:
                    nfcom:
                      id: 456e7890-e89b-12d3-a456-426614174111
                      number: 124
                      series: "001"
                      model: 62
                      status: SUBMISSION_ERROR
                      nfcom_key: null
                      protocol_number: null
                      environment: homologacao
                      issue_date: 2025-09-05T11:00:00.000Z
                      created_at: 2025-09-09T11:00:00.000Z
                      updated_at: 2025-09-09T11:05:00.000Z
                      client:
                        name: Maria Santos
                        document: "98765432100"
                        email: maria@email.com
                      documents:
                        xml_url: null
                        pdf_url: null
                pending_submission_status:
                  summary: NFCom Aguardando Envio
                  value:
                    nfcom:
                      id: 789e0123-e89b-12d3-a456-426614174222
                      number: 125
                      series: "001"
                      model: 62
                      status: PENDING_SUBMISSION
                      nfcom_key: null
                      protocol_number: null
                      environment: homologacao
                      issue_date: 2025-09-05T12:00:00.000Z
                      created_at: 2025-09-09T12:00:00.000Z
                      updated_at: 2025-09-09T12:00:00.000Z
                      client:
                        name: Pedro Oliveira
                        document: "11122233344"
                        email: pedro@email.com
                      documents:
                        xml_url: https://api.nfcom.telcomnfe.com.br/v2/invoices/789e0123-e89b-12d3-a456-426614174222/documents/xml
                        pdf_url: https://api.nfcom.telcomnfe.com.br/v2/invoices/789e0123-e89b-12d3-a456-426614174222/documents/pdf
        "400":
          description: Parâmetros de busca inválidos ou ausentes
          content:
            application/json:
              schema: *a44
              examples:
                no_parameters:
                  summary: Nenhum parâmetro fornecido
                  value:
                    status: error
                    message: Pelo menos um parâmetro de busca deve ser informado
                    error: VALIDATION_ERROR
                invalid_series:
                  summary: Série inválida
                  value:
                    status: error
                    message: Série deve conter apenas números inteiros
                    error: VALIDATION_ERROR
        "401":
          description: Token de autenticação inválido ou expirado
          content:
            application/json:
              schema: *a45
        "404":
          description: NFCom não encontrada com os critérios informados
          content:
            application/json:
              schema: *a44
              example:
                status: error
                message: NFCom não encontrada com os critérios informados
                error: NOT_FOUND
  /v2/invoices/{id}/logs:
    get:
      tags:
        - NFCom Consultas
      summary: Logs da NFCom
      description: |
        Consulta logs detalhados de processamento da NFCom.

        ### 📋 **Informações dos Logs:**
        - ✅ **Histórico completo** de operações
        - ✅ **Logs de erro** detalhados
        - ✅ **Timestamps precisos** de cada evento
        - ✅ **Status de transmissão** SEFAZ

        ### 🎯 **Para Desenvolvedores:**
        - Essential para debugging de problemas
        - Rastrear todo ciclo de vida da NFCom
        - Identificar falhas de transmissão/validação
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Logs retornados com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: f2a3b4c5-8d9e-0123-fghi-456789012345
                        timestamp:
                          type: string
                          format: date-time
                          example: 2024-01-15T10:30:00Z
                          description: Data/hora do evento
                        level:
                          type: string
                          enum:
                            - INFO
                            - WARN
                            - ERROR
                            - DEBUG
                          example: INFO
                          description: Nível do log
                        operation:
                          type: string
                          example: NFCOM_CREATION
                          description: Operação realizada
                        message:
                          type: string
                          example: NFCom criada e enfileirada para transmissão
                          description: Descrição do evento
                        details:
                          type: object
                          description: Detalhes específicos do evento
                          properties:
                            component:
                              type: string
                              example: CreateNfcomService
                            duration:
                              type: integer
                              example: 1250
                              description: Duração da operação em ms
                            request_id:
                              type: string
                              example: req_123456789
                            user_id:
                              type: string
                              format: uuid
                              example: 987e6543-e21d-32b1-a456-426614174987
                        sefaz_response:
                          type: object
                          description: Resposta da SEFAZ (quando aplicável)
                          properties:
                            protocol:
                              type: string
                              example: "135240000001234"
                            status_code:
                              type: integer
                              example: 100
                            status_message:
                              type: string
                              example: Autorizado o uso da NFCom
                            processing_time:
                              type: integer
                              example: 2340
                              description: Tempo de processamento SEFAZ em ms
                        error_details:
                          type: object
                          description: Detalhes de erro (quando aplicável)
                          properties:
                            error_code:
                              type: string
                              example: VALIDATION_ERROR
                            error_message:
                              type: string
                              example: Campo obrigatório não informado
                            field:
                              type: string
                              example: client.document
                            stack_trace:
                              type: string
                              example: Error at CreateNfcomService.execute:125
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
  /v2/invoices/consult-sefaz-status:
    post:
      tags:
        - NFCom Consultas
      summary: Consultar status na SEFAZ
      description: |
        Consulta o status atual da NFCom **diretamente na SEFAZ** (Receita Federal),
        usando a chave de acesso (44 dígitos) ou o ID interno.

        Informe `chaveNFCom` **ou** `nfcomId`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                chaveNFCom:
                  type: string
                  pattern: ^[0-9]{44}$
                  description: Chave de acesso da NFCom (44 dígitos)
                  example: "35240514200166000187620010000001231234567890"
                nfcomId:
                  type: string
                  format: uuid
                  description: ID interno da NFCom
                  example: 123e4567-e89b-12d3-a456-426614174000
            examples:
              porChave:
                summary: Por chave de acesso
                value:
                  chaveNFCom: "35240514200166000187620010000001231234567890"
              porId:
                summary: Por ID interno
                value:
                  nfcomId: 123e4567-e89b-12d3-a456-426614174000
      responses:
        "200":
          description: Consulta realizada
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  status:
                    type: string
                    example: "100"
                  message:
                    type: string
                    example: Autorizado o uso da NFCom
                  nfcomId:
                    type: string
                    format: uuid
                  chaveNFCom:
                    type: string
        "400":
          description: Informe chaveNFCom ou nfcomId
          content:
            application/json:
              schema: *a44
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a45
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
  /v2/invoices/send-files-async:
    post:
      tags:
        - NFCom Arquivos
      summary: Enviar NFCom por Email (Assíncrono)
      description: |
        Enfileira o envio de PDF e/ou XML por e-mail para uma ou mais NFCom.

        O destinatário é o e-mail do **tomador** já cadastrado na nota.
        Não há campos de assunto/mensagem no payload — o template é do sistema.

        ### Características
        - Processamento assíncrono via fila
        - Envio em lote (vários IDs)
        - `validateOnly` para validar sem enviar
        - Pelo menos um anexo: `includeXml` ou `includePdf` (ambos `true` por padrão)
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  minItems: 1
                  example:
                    - 123e4567-e89b-12d3-a456-426614174000
                    - 223e4567-e89b-12d3-a456-426614174001
                  description: |
                    IDs das NFCom a enviar por e-mail (obrigatório, mínimo 1).
                    O destinatário é o e-mail do tomador cadastrado na nota.
                includeXml:
                  type: boolean
                  default: true
                  example: true
                  description: Incluir XML no anexo (padrão `true`)
                includePdf:
                  type: boolean
                  default: true
                  example: true
                  description: |
                    Incluir PDF (DANFE) no anexo (padrão `true`).
                    Não pode ser `false` junto com `includeXml: false`.
                validateOnly:
                  type: boolean
                  default: false
                  example: false
                  description: |
                    Se `true`, apenas valida elegibilidade (e-mail, transmissão etc.)
                    sem enfileirar o envio.
            example:
              summary: Envio assíncrono de NFCom por email
              value:
                ids:
                  - 123e4567-e89b-12d3-a456-426614174000
                  - 223e4567-e89b-12d3-a456-426614174001
                includeXml: true
                includePdf: true
                validateOnly: false
      responses:
        "200":
          description: Enfileirado ou validado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  validateOnly:
                    type: boolean
                    example: false
                    description: Indica se a chamada foi só de validação
                  message:
                    type: string
                    example: Arquivos enfileirados para envio
                  requestId:
                    type: string
                    example: 123e4567-e89b-12d3-a456-426614174099
                    description: ID do lote (quando houver enfileiramento)
                  totalEnqueued:
                    type: integer
                    example: 2
                    description: Quantidade de NFCom enfileiradas
                  summary:
                    type: object
                    properties:
                      requested:
                        type: integer
                        example: 2
                      found:
                        type: integer
                        example: 2
                      notFound:
                        type: integer
                        example: 0
                      enqueued:
                        type: integer
                        example: 2
                      skipped:
                        type: integer
                        example: 0
                  nfcoms:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: 123e4567-e89b-12d3-a456-426614174000
                        number:
                          type: integer
                          example: 123
                        displayNumber:
                          type: string
                          example: "123"
                        clientName:
                          type: string
                          example: Cliente Exemplo
                        status:
                          type: string
                          enum:
                            - enqueued
                            - error
                          example: enqueued
                        message:
                          type: string
                          example: Enfileirado para envio
                        reason:
                          type: string
                          enum:
                            - not_found
                            - no_email
                            - not_transmitted
                            - other
                          description: Motivo quando status = error
        "400":
          description: Dados inválidos para envio
          content:
            application/json:
              schema: *a44
  /v2/invoices/download-xml-batch:
    post:
      tags:
        - NFCom Arquivos
      summary: Download XMLs em Lote
      description: |
        Gera um arquivo ZIP com os XMLs das NFCom informadas.

        Critérios (pelo menos um):
        - `ids`: lista de UUIDs
        - `startDate` / `endDate`: período (ISO date)

        ### Características
        - Resposta binária (`application/zip`)
        - Header `X-Total-Files` com a quantidade de arquivos no ZIP
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: |
                Informe **IDs** e/ou um **período** (`startDate` / `endDate`).
                Pelo menos um critério é obrigatório (`ids` **ou** `startDate` **ou** `endDate`).
              properties:
                ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  minItems: 1
                  example:
                    - 123e4567-e89b-12d3-a456-426614174000
                    - 223e4567-e89b-12d3-a456-426614174001
                  description: IDs das NFCom para download (opcional se informar datas)
                startDate:
                  type: string
                  format: date
                  example: 2024-08-01
                  description: Data inicial do período (ISO date, opcional)
                endDate:
                  type: string
                  format: date
                  example: 2024-08-31
                  description: Data final do período (ISO date, opcional)
            examples:
              byIds:
                summary: Download em lote por IDs
                value:
                  ids:
                    - 123e4567-e89b-12d3-a456-426614174000
                    - 223e4567-e89b-12d3-a456-426614174001
              byDate:
                summary: Download em lote por período
                value:
                  startDate: 2024-08-01
                  endDate: 2024-08-31
      responses:
        "200":
          description: Arquivo ZIP gerado com sucesso
          content:
            application/zip:
              schema:
                type: string
                format: binary
                description: Arquivo ZIP contendo os XMLs
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="nfcom_xmls_20240115.zip"
            X-Total-Files:
              schema:
                type: integer
                example: 2
        "400":
          description: Parâmetros inválidos
          content:
            application/json:
              schema: *a44
  /v2/invoices/download-xml-async:
    post:
      tags:
        - NFCom Arquivos
        - NFS-e Arquivos
      summary: Baixar XMLs em lote (assíncrono)
      description: |
        Gera um ZIP com os XMLs de várias notas, fora do tempo da requisição.
        Serve para NFCom e para NFS-e (`documentType`).

        Informe **ou** `ids` **ou** o período (`startDate` e `endDate`), nunca os dois.
        No período, NFCom usa a data de emissão e NFS-e usa a competência.

        Entram no ZIP só notas autorizadas, canceladas ou substituídas, do ambiente atual da empresa.

        ### Fluxo
        1. Chame este endpoint e guarde o `requestId`.
        2. Aguarde o processamento. O painel recebe uma notificação quando o ZIP fica pronto.
        3. Baixe o ZIP em `GET /v2/invoices/download-xml-result/{requestId}`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: IDs das notas. Não use junto com o período.
                startDate:
                  type: string
                  format: date
                  example: 2026-09-01
                endDate:
                  type: string
                  format: date
                  example: 2026-09-30
                documentType:
                  type: string
                  enum:
                    - nfcom
                    - nfse
                  default: nfcom
                xmlType:
                  type: string
                  enum:
                    - processed
                    - send
                  default: processed
                  description: |
                    Só para NFCom. `processed` é o XML autorizado (nfcomProc).
                    `send` é o XML assinado enviado à SEFAZ.
            examples:
              nfse_periodo:
                summary: NFS-e de um mês
                value:
                  documentType: nfse
                  startDate: 2026-09-01
                  endDate: 2026-09-30
              nfcom_ids:
                summary: NFCom por IDs
                value:
                  documentType: nfcom
                  ids:
                    - 2b5d8f0e-1c3a-4e6b-9f7d-0a1b2c3d4e5f
      responses:
        "200":
          description: Download enfileirado
          content:
            application/json:
              schema:
                type: object
                properties:
                  requestId:
                    type: string
                    example: xml_download_1790000000000_k3j9x2abc
                  totalEnqueued:
                    type: integer
                    example: 42
                  message:
                    type: string
                    example: 42 XML(s) adicionado(s) à fila de processamento
                  nfcoms:
                    type: array
                    description: Situação de cada nota no lote. O nome se mantém `nfcoms` também para NFS-e.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        number:
                          type: integer
                        series:
                          type: string
                        status:
                          type: string
                          enum:
                            - enqueued
                            - error
                        message:
                          type: string
        "400":
          description: Informe IDs ou período, não os dois
          content:
            application/json:
              schema: *a44
        "401":
          description: Não autorizado
        "403":
          description: NFS-e não habilitada para a empresa
  /v2/invoices/download-xml-result/{requestId}:
    get:
      tags:
        - NFCom Arquivos
        - NFS-e Arquivos
      summary: Baixar ZIP do lote de XMLs
      description: |
        Baixa o ZIP gerado por `POST /v2/invoices/download-xml-async`.
        Retorna 404 enquanto o ZIP não estiver pronto ou depois que ele expirar.
      parameters:
        - name: requestId
          in: path
          required: true
          description: "`requestId` devolvido pelo pedido de download."
          schema:
            type: string
            example: xml_download_1790000000000_k3j9x2abc
      responses:
        "200":
          description: ZIP com os XMLs
          content:
            application/zip:
              schema:
                type: string
                format: binary
        "401":
          description: Não autorizado
        "404":
          description: ZIP não encontrado ou expirado
  /v2/invoices/{id}/email-history:
    get:
      tags:
        - NFCom Arquivos
      summary: Histórico de Emails
      description: |
        Consulta o histórico de emails enviados para uma NFCom.

        ### 📧 **Informações Retornadas:**
        - ✅ **Dados do envio**: Data, destinatário, status
        - ✅ **Tentativas**: Sucessos e falhas
        - ✅ **Logs de erro**: Detalhes de problemas
        - ✅ **Anexos enviados**: PDF, XML incluídos

        ### 🎯 **Para Desenvolvedores:**
        - Use para auditorias e troubleshooting
        - Verificar se emails foram entregues
        - Identificar problemas de envio
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Histórico de emails retornado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                          example: e1f2a3b4-7c8d-9012-efab-345678901234
                        sentAt:
                          type: string
                          format: date-time
                          example: 2024-01-15T10:30:00Z
                          description: Data/hora do envio
                        recipient:
                          type: string
                          format: email
                          example: cliente@empresa.com
                          description: Email do destinatário
                        subject:
                          type: string
                          example: Sua Nota Fiscal de Comunicação
                          description: Assunto do email enviado
                        status:
                          type: string
                          enum:
                            - SENT
                            - DELIVERED
                            - FAILED
                            - BOUNCED
                            - COMPLAINT
                          example: SENT
                          description: Status do envio
                        attachments:
                          type: array
                          items:
                            type: string
                            enum:
                              - PDF
                              - XML
                          example:
                            - PDF
                            - XML
                          description: Tipos de anexos incluídos
                        attempts:
                          type: integer
                          example: 1
                          description: Número de tentativas de envio
                        lastAttempt:
                          type: string
                          format: date-time
                          example: 2024-01-15T10:30:00Z
                          description: Data/hora da última tentativa
                        errorMessage:
                          type: string
                          example: null
                          description: Mensagem de erro (se houver)
                        deliveryDetails:
                          type: object
                          properties:
                            messageId:
                              type: string
                              example: 0000014a-f4d1-4bf0-b0ee-1234567890ab-000000
                            provider:
                              type: string
                              example: AWS SES
                            deliveredAt:
                              type: string
                              format: date-time
                              example: 2024-01-15T10:31:25Z
        "404":
          description: NFCom não encontrada
          content:
            application/json:
              schema: *a44
  /v2/invoices/{id}/pdf-url:
    get:
      tags:
        - NFCom Arquivos
      summary: Obter URL do PDF
      description: |
        Retorna URL temporária para visualização ou download do PDF da NFCom.

        ### 🔗 **Características:**
        - ✅ **URL temporária** (válida por 1 hora)
        - ✅ **Acesso direto** sem autenticação adicional
        - ✅ **PDF otimizado** para impressão
        - ✅ **Cache inteligente** para performance

        ### 🎯 **Para Desenvolvedores:**
        - URL pode ser usada em iframes
        - Ideal para preview em interfaces web
        - Regenere URL após expiração
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
        - name: forceRegenerate
          in: query
          required: false
          description: Se true, força a regeneração do PDF
          schema:
            type: boolean
            default: false
        - name: expiresIn
          in: query
          required: false
          description: Validade da URL em segundos (300 a 86400)
          schema:
            type: integer
            minimum: 300
            maximum: 86400
            default: 3600
      responses:
        "200":
          description: URL do PDF gerada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      pdfUrl:
                        type: string
                        format: uri
                        example: https://files.telcomnfe.com.br/temp/nfcom_12345_20240115.pdf?token=abc123def456
                        description: URL temporária do PDF (válida por 1 hora)
                      expiresAt:
                        type: string
                        format: date-time
                        example: 2024-01-15T11:30:00Z
                        description: Data/hora de expiração da URL
                      fileName:
                        type: string
                        example: nfcom_12345_20240115.pdf
                        description: Nome sugerido para download
                      fileSize:
                        type: integer
                        example: 524288
                        description: Tamanho do arquivo em bytes
                      generatedAt:
                        type: string
                        format: date-time
                        example: 2024-01-15T10:30:00Z
                        description: Data/hora de geração do PDF
                      accessInstructions:
                        type: string
                        example: URL válida por 1 hora. Para acesso permanente, use o endpoint de download direto.
                        description: Instruções de uso da URL
        "404":
          description: NFCom ou PDF não encontrado
          content:
            application/json:
              schema: *a44
  /v2/invoices/{id}/download-pdf:
    get:
      tags:
        - NFCom Arquivos
      summary: Download PDF
      description: |
        Faz download direto do PDF da NFCom.

        ### 📄 **Características:**
        - ✅ **Download direto** sem URLs temporárias
        - ✅ **PDF de alta qualidade** para impressão
        - ✅ **Headers corretos** para browser
        - ✅ **Validação de permissões** automática

        ### 🎯 **Para Desenvolvedores:**
        - Use para downloads programáticos
        - Ideal para integrações que precisam do arquivo
        - Response em binary/PDF
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
        - name: forceRegenerate
          in: query
          required: false
          description: Se true, força a regeneração do PDF
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: PDF retornado com sucesso
          content:
            application/pdf:
              schema:
                type: string
                format: binary
                description: Arquivo PDF da NFCom
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="nfcom_12345_20240115.pdf"
        "404":
          description: NFCom ou PDF não encontrado
          content:
            application/json:
              schema: *a44
  /v2/invoices/{id}/download-xml:
    get:
      tags:
        - NFCom Arquivos
      summary: Download XML
      description: |
        Faz download do XML assinado da NFCom.

        ### 📄 **Características:**
        - ✅ **XML assinado** digitalmente válido
        - ✅ **Autorizado pela SEFAZ** (se aplicável)
        - ✅ **Formato padrão** para sistemas contábeis
        - ✅ **Encoding UTF-8** correto

        ### 🎯 **Para Desenvolvedores:**
        - Use para integrações contábeis/fiscais
        - XML contém todas as informações oficiais
        - Válido para auditoria fiscal
      parameters:
        - name: id
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: XML retornado com sucesso
          content:
            application/xml:
              schema:
                type: string
                description: XML assinado da NFCom
          headers:
            Content-Disposition:
              schema:
                type: string
                example: attachment; filename="nfcom_12345_20240115.xml"
        "404":
          description: NFCom ou XML não encontrado
          content:
            application/json:
              schema: *a44
  /v2/invoices/{nfcomId}/documents/{type}:
    get:
      tags:
        - NFCom Arquivos
      summary: Obter URL do XML ou PDF
      description: |
        Retorna (ou redireciona para) o XML ou o PDF (DANFE) da NFCom.

        Com `public=true`, a resposta contém a URL pública direta
        (`storage.nfcom.telcomnfe.com.br`) em vez de um redirecionamento.
      parameters:
        - name: nfcomId
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
        - name: type
          in: path
          required: true
          description: Tipo do documento
          schema:
            type: string
            enum:
              - xml
              - pdf
        - name: public
          in: query
          required: false
          description: Se true, retorna a URL pública sem redirecionar
          schema:
            type: boolean
            default: false
      responses:
        "200":
          description: URL do documento ou redirecionamento
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                    format: uri
                    example: https://storage.nfcom.telcomnfe.com.br/...
                  type:
                    type: string
                    enum:
                      - xml
                      - pdf
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a45
        "404":
          description: Documento não encontrado
          content:
            application/json:
              schema: *a44
  /v2/invoices/{nfcomId}/public-documents/{type}:
    get:
      tags:
        - NFCom Arquivos
      summary: URL pública do XML ou PDF
      description: |
        Retorna a URL pública direta do XML ou PDF no storage
        (`storage.nfcom.telcomnfe.com.br`), sem redirecionamento.
      parameters:
        - name: nfcomId
          in: path
          required: true
          description: ID da NFCom (UUID)
          schema:
            type: string
            format: uuid
        - name: type
          in: path
          required: true
          description: Tipo do documento
          schema:
            type: string
            enum:
              - xml
              - pdf
      responses:
        "200":
          description: URL pública gerada
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
                    format: uri
                    example: https://storage.nfcom.telcomnfe.com.br/...
                  type:
                    type: string
                    enum:
                      - xml
                      - pdf
                  expiresIn:
                    type: integer
                    description: Validade da URL em segundos
                    example: 3600
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a45
        "404":
          description: Documento não encontrado
          content:
            application/json:
              schema: *a44
  /v2/invoices/calculate:
    post:
      tags:
        - NFCom
      summary: Calcular valores de NFCom
      description: |
        Calcula os valores de impostos e totais de uma NFCom antes de criá-la.

        ### 🧮 **Finalidade:**
        - ✅ **Pré-visualização** de valores antes da criação
        - ✅ **Validação de cálculos** tributários
        - ✅ **Simulação** de diferentes cenários fiscais

        ### 💡 **Para Desenvolvedores:**
        - Use antes de criar a NFCom para verificar valores
        - Ideal para interfaces que mostram prévia de impostos
        - Não salva dados, apenas retorna cálculos
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - items
                - tpFat
              properties:
                items:
                  type: array
                  minItems: 1
                  items:
                    type: object
                    required:
                      - description
                      - unitValue
                      - quantity
                      - cst
                    properties:
                      description:
                        type: string
                        example: Internet Banda Larga 100MB
                        description: Descrição do serviço (obrigatório)
                      unitValue:
                        type: number
                        example: 89.9
                        description: Valor unitário (obrigatório)
                      quantity:
                        type: number
                        example: 1
                        description: Quantidade (obrigatório)
                      discount:
                        type: number
                        default: 0
                        example: 5
                        description: Valor de desconto (opcional)
                      cst:
                        type: string
                        enum:
                          - "00"
                          - "20"
                          - "40"
                          - "41"
                          - "90"
                        example: "00"
                        description: CST do ICMS (obrigatório)
                tpFat:
                  type: string
                  enum:
                    - "0"
                    - "1"
                    - "2"
                  example: "0"
                  description: |
                    Tipo de faturamento (obrigatório):
                    - '0': Normal
                    - '1': Centralizado
                    - '2': Cofaturamento
            example:
              summary: Exemplo de cálculo de NFCom
              value:
                items:
                  - description: Internet Banda Larga 100MB
                    unitValue: 89.9
                    quantity: 1
                    discount: 5
                    cst: "00"
                tpFat: "0"
      responses:
        "200":
          description: Cálculos realizados com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  data:
                    type: object
                    properties:
                      totalValue:
                        type: number
                        example: 84.9
                        description: Valor total da NFCom
                      totalTaxes:
                        type: number
                        example: 23.5
                        description: Total de impostos
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            description:
                              type: string
                              example: Internet Banda Larga 100MB
                            calculatedTaxes:
                              type: object
                              properties:
                                icms:
                                  type: number
                                  example: 15.28
                                pis:
                                  type: number
                                  example: 1.4
                                cofins:
                                  type: number
                                  example: 6.44
        "400":
          description: Dados inválidos para cálculo
          content:
            application/json:
              schema: *a44
  /webhook/nfcom-notifications:
    post:
      tags:
        - Webhooks (Implementação)
      summary: "[PARA IMPLEMENTAÇÃO] Endpoint de Webhook NFCom"
      description: >
        **⚠️ ESTE NÃO É UM ENDPOINT DA API TELCOMNFE**


        Esta documentação descreve como **SEU SISTEMA** deve implementar o endpoint para receber notificações de
        webhooks do TelcomNFe.


        ### 🎯 **O que você precisa implementar:**


        Um endpoint HTTP POST que:

        - ✅ Aceita o payload de notificação NFCom

        - ✅ Responde com status 200-299 para confirmar recebimento

        - ✅ Processa rapidamente (< 30 segundos)

        - ✅ É idempotente (pode receber o mesmo evento várias vezes)


        ### 🔄 **Fluxo de Notificação:**


        1. **TelcomNFe** → mudança de status da NFCom

        2. **TelcomNFe** → envia POST para sua URL configurada

        3. **Seu Sistema** → processa notificação

        4. **Seu Sistema** → responde 200 OK

        5. **TelcomNFe** → confirma entrega ou retry se erro


        ### 💻 **URL de Exemplo:**

        ```

        https://seu-sistema.com/webhook/nfcom-notifications

        ```


        ### 🔐 Validar a assinatura (NFCom e NFS-e)

        1. Gere o segredo em **Configurações → Integrações → Segredo de assinatura do webhook**
           (formato `whsec_...`). O segredo completo só aparece no momento da geração (fica cifrado no
           nosso banco); depois o painel mostra só uma prévia. Ao gerar um novo, durante 24 horas os
           webhooks levam também `X-TelcomNFe-Signature-256-Previous`, assinado com o segredo anterior:
           aceite qualquer um dos dois enquanto atualiza o seu sistema.
        2. Leia o **corpo bruto** da requisição (antes de fazer parse do JSON).

        3. Calcule `HMAC-SHA256(segredo, X-TelcomNFe-Timestamp + "." + corpo_bruto)` em hexadecimal.

        4. Compare com `X-TelcomNFe-Signature-256` usando comparação de tempo constante.

        5. Rejeite se o timestamp estiver a mais de 5 minutos do seu relógio (proteção contra replay).


        ```js

        const crypto = require('crypto');

        app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
          const timestamp = req.get('X-TelcomNFe-Timestamp');
          const signature = req.get('X-TelcomNFe-Signature-256') || '';
          const raw = req.body.toString('utf8');
          const expected = crypto.createHmac('sha256', process.env.TELCOMNFE_WEBHOOK_SECRET)
            .update(`${timestamp}.${raw}`).digest('hex');
          const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
          const valid = signature.length === expected.length &&
            crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
          if (!fresh || !valid) return res.status(401).end();
          const event = JSON.parse(raw);
          // ... processe event.nfse ou event.nfcom
          res.status(200).end();
        });

        ```


        ```python

        import hmac, hashlib, time

        def valido(raw: bytes, timestamp: str, assinatura: str, segredo: str) -> bool:
            if abs(time.time() - int(timestamp)) > 300:
                return False
            esperado = hmac.new(segredo.encode(), f"{timestamp}.".encode() + raw, hashlib.sha256).hexdigest()
            return hmac.compare_digest(esperado, assinatura)
        ```


        ```php

        <?php

        $raw = file_get_contents('php://input');

        $timestamp = $_SERVER['HTTP_X_TELCOMNFE_TIMESTAMP'] ?? '';

        $assinatura = $_SERVER['HTTP_X_TELCOMNFE_SIGNATURE_256'] ?? '';

        $segredo = getenv('TELCOMNFE_WEBHOOK_SECRET');


        $esperado = hash_hmac('sha256', $timestamp . '.' . $raw, $segredo);

        $recente = ctype_digit($timestamp) && abs(time() - (int) $timestamp) <= 300;

        if (!$recente || !hash_equals($esperado, $assinatura)) {
            http_response_code(401);
            exit;
        }

        $evento = json_decode($raw, true);

        // Idempotência: ignore se $evento['event_id'] já foi processado.

        // ... processe $evento['nfse'] ou $evento['nfcom']

        http_response_code(200);

        ```


        ### 🔁 Quando o webhook da NFS-e é (re)enviado

        - Uma vez por mudança de status, inclusive os intermediários (`nfse_created`, `nfse_pending`,
          `nfse_processing`, `nfse_pending_consult`). Só `nfse_authorized`, `nfse_rejected`,
          `nfse_canceled`, `nfse_cancellation_error` e `nfse_substituted` são finais.
        - Cada evento tem um `event_id` (também no header `X-TelcomNFe-Event-ID`), o mesmo em todas as
          tentativas de entrega do evento. Use-o para descartar repetições.
        - Falha na entrega (resposta fora de 2xx, timeout de 30 s ou erro de conexão): 5 novas
          tentativas, 5 min, 15 min, 30 min, 1 h e 3 h depois da anterior. Esgotadas, o evento não é
          reenviado sozinho.
        - O mesmo status não é notificado duas vezes seguidas. Os eventos podem chegar fora de ordem:
          use `timestamp`, `nfse.previous_status` e, na dúvida, `GET /v2/invoices/nfse/{id}`.
        - Um evento intermediário pode não ser enviado se a nota já tiver avançado quando ele seria
          enfileirado (ex.: `pending` → `processing` → `authorized` em menos de um segundo). O evento
          final sempre sai, e `nfse.previous_status` mostra o último status notificado.
        - Consultar a nota (refresh) só notifica se a consulta trouxe a nota da SEFIN **e** o último
          evento notificado for diferente do status atual: o status mudou, ou o evento anterior estava
          errado ou não chegou a ser entregue (ex.: uma rejeição falsa corrigida para autorizada).
        - Consulta que falha (gateway fora, L9999, timeout) nunca altera a nota nem envia webhook.

        - Quando a prefeitura recebe a DPS mas não confirma o resultado (L9999 com erro de banco na leitura,
          HTTP 5xx ou timeout depois do envio), a nota vai para `pending_consult` (evento
          `nfse_pending_consult`) e é consultada de novo automaticamente até sair `nfse_authorized` ou
          `nfse_rejected`. Não retransmita nem emita outra nota nesse meio-tempo.
        - Se o mesmo evento já foi entregue, está na fila ou esgotou as tentativas, a consulta não o reenvia.


        O header legado `X-TelcomNFe-Signature` (SHA-256 do corpo sem segredo) continua sendo enviado

        sem mudança, mas qualquer um consegue gerá-lo: não use para autenticar a origem.
      parameters:
        - name: X-TelcomNFe-Event
          in: header
          required: false
          schema:
            type: string
            example: nfcom_authorized
          description: Tipo de evento da notificação
        - name: X-TelcomNFe-NFCom-ID
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: ID da NFCom que gerou a notificação
        - name: X-TelcomNFe-NFSe-ID
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: ID da NFS-e que gerou a notificação (só nos eventos `nfse_*`)
        - name: X-TelcomNFe-Event-ID
          in: header
          required: false
          schema:
            type: string
            example: 3b9f0c2e-6a1d-4c8e-9f2a-7d5e1b4c8a90
          description: |
            Identificador único do evento da NFS-e, igual ao `event_id` do corpo e repetido em todas as
            tentativas de entrega. Use para descartar repetições. Só nos eventos `nfse_*`.
        - name: X-TelcomNFe-Customer-ID
          in: header
          required: false
          schema:
            type: string
            format: uuid
          description: ID do cliente no sistema TelcomNFe
        - name: X-TelcomNFe-Signature
          in: header
          required: false
          schema:
            type: string
          description: |
            Legado: SHA-256 (hex) do corpo, **sem segredo** — só detecta corrupção, não prova a origem.
            Mantido por compatibilidade. Para segurança, valide o `X-TelcomNFe-Signature-256`.
        - name: X-TelcomNFe-Timestamp
          in: header
          required: false
          schema:
            type: string
            example: "1791403200"
          description: Unix timestamp (segundos) do envio. Só vem quando a empresa tem segredo de webhook.
        - name: X-TelcomNFe-Signature-256
          in: header
          required: false
          schema:
            type: string
            example: 3f1c9a...e7
          description: |
            HMAC-SHA256 (hex) com o **segredo da empresa** sobre `timestamp + "." + corpo bruto`.
            Só vem quando a empresa gerou o segredo em Configurações → Integrações.
            Se o segredo não puder ser lido no envio, o webhook não sai sem assinatura: é reenviado depois.
        - name: X-TelcomNFe-Signature-256-Previous
          in: header
          required: false
          schema:
            type: string
          description: |
            Mesmo cálculo do `X-TelcomNFe-Signature-256`, mas com o segredo **anterior**. Só vem nas
            24 horas seguintes à geração de um novo segredo.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Payload de notificação enviado via webhook quando há mudanças de status em NFComs
              required:
                - event
                - timestamp
                - nfcom
                - message
              properties:
                event:
                  type: string
                  enum:
                    - nfcom_created
                    - nfcom_submitting
                    - nfcom_submitted
                    - nfcom_authorized
                    - nfcom_rejected
                    - nfcom_pending_cancellation
                    - nfcom_cancelling
                    - nfcom_cancelled
                    - nfcom_cancellation_error
                  description: Tipo de evento da NFCom. A autorização pela SEFAZ é notificada como nfcom_submitted (com nfcom.status
                    submitted, ou transmitted no envio síncrono /v2/invoices/nfcom/full/sync e na API legada).
                    nfcom_authorized consta da lista mas não é enviado no fluxo normal; não dependa dele para detectar a
                    autorização.
                  example: nfcom_submitted
                timestamp:
                  type: string
                  format: date-time
                  description: Data/hora da notificação (ISO 8601)
                  example: 2025-08-29T03:06:00.000Z
                message:
                  type: string
                  description: Mensagem descritiva do evento
                  example: NFCom foi autorizada pela SEFAZ
                nfcom:
                  type: object
                  description: Dados da NFCom incluídos na notificação
                  required:
                    - id
                    - number
                    - series
                    - model
                    - status
                    - issue_date
                    - client
                  properties:
                    id:
                      type: string
                      format: uuid
                      description: ID único da NFCom no sistema
                      example: 123e4567-e89b-12d3-a456-426614174000
                    number:
                      type: integer
                      description: Número da NFCom
                      example: 123456
                    series:
                      type: string
                      description: Série da NFCom
                      example: "1"
                    model:
                      type: integer
                      enum:
                        - 21
                        - 62
                      description: Modelo da NFCom (21 ou 62)
                      example: 62
                    status:
                      type: string
                      enum:
                        - created
                        - pending_submission
                        - submitting
                        - submitted
                        - transmitted
                        - pending_cancellation
                        - cancelling
                        - cancelled
                        - replaced
                        - submission_error
                        - cancellation_error
                        - validated
                      description: "Status da NFCom no momento do evento, em minúsculas (equivale ao status da API: submitted = SUBMITTED,
                        created = DRAFT etc.). submitted = autorizada pela SEFAZ (é o status final de uma nota válida,
                        gravado no retorno da autorização; o nome vem de \"transmitida\" e não quer dizer que ainda
                        aguarda a SEFAZ). transmitted = só no envio síncrono (POST /v2/invoices/nfcom/full/sync e API
                        legada /v2/invoices/nfcom/legacy/create), no evento nfcom_submitted enviado ao fim da
                        requisição, depois que a SEFAZ autorizou a nota (na API ela já está SUBMITTED). Não é
                        intermediário: nesse fluxo não chega outro webhook com submitted; trate transmitted como
                        autorizada. Se a SEFAZ rejeitar no envio síncrono, chegam nfcom_rejected (submission_error) e
                        nfcom_created (created), e a requisição retorna erro. Demais: created rascunho; validated
                        legado, não é gravado nas emissões atuais; pending_submission na fila de envio; submitting em
                        envio à SEFAZ; submission_error rejeitada ou com erro no envio; pending_cancellation e
                        cancelling cancelamento em andamento; cancelled cancelada; cancellation_error cancelamento
                        recusado (a nota continua autorizada); replaced substituída por outra NFCom."
                      example: submitted
                    nfcom_key:
                      type: string
                      pattern: ^[0-9]{44}$
                      description: Chave de acesso da NFCom (44 dígitos)
                      example: "35250100000000000001620000123456789012345"
                    protocol_number:
                      type: string
                      description: Número do protocolo da SEFAZ
                      example: "135250001234567"
                    environment:
                      type: string
                      enum:
                        - homologacao
                        - producao
                      description: Ambiente de transmissão da NFCom
                      example: producao
                    issue_date:
                      type: string
                      format: date-time
                      description: Data de emissão da NFCom (ISO 8601)
                      example: 2025-08-29T03:06:00.000Z
                    client:
                      type: object
                      description: Dados do cliente da NFCom
                      required:
                        - name
                        - document
                      properties:
                        name:
                          type: string
                          description: Nome do cliente
                          example: Empresa de Telecomunicações LTDA
                        document:
                          type: string
                          description: CPF (11 dígitos) ou CNPJ (14 caracteres, numérico ou alfanumérico)
                          example: "12345678000190"
                    documents:
                      type: object
                      description: URLs dos documentos (presentes nos eventos authorized, cancelled e submitted)
                      properties:
                        xml_url:
                          type: string
                          format: uri
                          description: XML processado (proc) ou XML de envio
                        pdf_url:
                          type: string
                          format: uri
                          description: DANFE em PDF
                        event_xml_url:
                          type: string
                          format: uri
                          description: XML do evento (cancelamento, etc.)
                        event_response_xml_url:
                          type: string
                          format: uri
                          description: XML de retorno da SEFAZ para o evento
                    error:
                      type: object
                      description: Detalhes do erro quando o último evento falhou
                      properties:
                        code:
                          type: string
                          example: "539"
                        message:
                          type: string
                          example: "Rejeição: CNPJ do destinatário inválido"
                        event_type:
                          type: string
                          example: Envio
                        attempt_number:
                          type: integer
                          example: 1
            examples:
              nfcomAuthorized:
                summary: NFCom Autorizada pela SEFAZ
                value:
                  event: nfcom_authorized
                  timestamp: 2025-08-29T14:30:25.123Z
                  message: NFCom foi autorizada pela SEFAZ com sucesso
                  nfcom:
                    id: 123e4567-e89b-12d3-a456-426614174000
                    number: 123456
                    series: "1"
                    model: 62
                    status: autorizada
                    nfcom_key: "35250100000000000001620000123456789012345"
                    protocol_number: "135250001234567"
                    environment: producao
                    issue_date: 2025-08-29T14:30:00.000Z
                    client:
                      name: Empresa de Telecomunicações LTDA
                      document: "12345678000190"
              nfcomRejected:
                summary: NFCom Rejeitada pela SEFAZ
                value:
                  event: nfcom_rejected
                  timestamp: 2025-08-29T14:31:45.456Z
                  message: NFCom foi rejeitada pela SEFAZ - verificar dados fiscais
                  nfcom:
                    id: 123e4567-e89b-12d3-a456-426614174001
                    number: 123457
                    series: "1"
                    model: 62
                    status: rejeitada
                    nfcom_key: "35250100000000000001620000123457789012346"
                    protocol_number: null
                    environment: homologacao
                    issue_date: 2025-08-29T14:31:00.000Z
                    client:
                      name: Cliente Teste LTDA
                      document: "98765432000123"
              nfcomCreated:
                summary: NFCom Criada no Sistema
                value:
                  event: nfcom_created
                  timestamp: 2025-08-29T14:25:10.789Z
                  message: Nova NFCom foi criada e está pronta para envio
                  nfcom:
                    id: 123e4567-e89b-12d3-a456-426614174002
                    number: 123458
                    series: "1"
                    model: 62
                    status: draft
                    nfcom_key: null
                    protocol_number: null
                    environment: producao
                    issue_date: 2025-08-29T14:25:00.000Z
                    client:
                      name: Telecomunicações Sul LTDA
                      document: "11223344000155"
              nfcomCancelled:
                summary: NFCom Cancelada
                value:
                  event: nfcom_cancelled
                  timestamp: 2025-08-29T15:45:30.321Z
                  message: NFCom foi cancelada com sucesso
                  nfcom:
                    id: 123e4567-e89b-12d3-a456-426614174003
                    number: 123459
                    series: "1"
                    model: 62
                    status: cancelada
                    nfcom_key: "35250100000000000001620000123459789012347"
                    protocol_number: "135250001234568"
                    environment: producao
                    issue_date: 2025-08-29T15:45:00.000Z
                    client:
                      name: Internet Fibra LTDA
                      document: "55667788000199"
      responses:
        "200":
          description: Notificação recebida e processada com sucesso
          content:
            application/json:
              schema:
                type: object
                description: Resposta esperada do endpoint de webhook
                properties:
                  success:
                    type: boolean
                    description: Indica se a notificação foi processada com sucesso
                    example: true
                  message:
                    type: string
                    description: Mensagem de confirmação
                    example: Notificação recebida e processada com sucesso
                  processedAt:
                    type: string
                    format: date-time
                    description: Timestamp do processamento
                    example: 2025-08-29T03:06:15.000Z
        "400":
          description: Payload inválido ou campos obrigatórios ausentes
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: Payload inválido - campo 'event' é obrigatório
                  received:
                    type: object
                    description: Dados recebidos (para debug)
        "500":
          description: Erro interno no processamento da notificação
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: false
                  message:
                    type: string
                    example: Erro interno ao processar notificação
                  error:
                    type: string
                    example: Database connection failed
  /clients:
    get:
      tags:
        - Clientes
      summary: Listar clientes
      description: |
        Lista os clientes das notas fiscais da empresa com filtros e paginação.
        Retorna também a contagem total para paginação.

        Observação: a resposta retorna o array `clients` e o total em `count`.
      parameters:
        - name: page
          in: query
          description: Número da página (paginação)
          required: false
          schema:
            type: integer
            default: 0
        - name: rowsPerPage
          in: query
          description: Itens por página
          required: false
          schema:
            type: integer
            default: 10
        - name: columnOrder
          in: query
          description: Campo de ordenação (ex. name, document, created_at)
          required: false
          schema:
            type: string
        - name: order
          in: query
          description: Direção da ordenação (asc ou desc)
          required: false
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - name: filterCode
          in: query
          description: Filtro por código do cliente
          required: false
          schema:
            type: string
        - name: filterName
          in: query
          description: Filtro por nome do cliente
          required: false
          schema:
            type: string
        - name: filterEmail
          in: query
          description: Filtro por email do cliente
          required: false
          schema:
            type: string
        - name: filterDocument
          in: query
          description: Filtro por CPF/CNPJ do cliente
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Lista de clientes retornada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  clients:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                        company:
                          type: string
                        document:
                          type: string
                        code:
                          type: string
                          nullable: true
                        indicatorIe:
                          type: integer
                          nullable: true
                        ie_rg:
                          type: string
                        im:
                          type: string
                        site:
                          type: string
                        taxation_system:
                          type: string
                        type:
                          type: string
                        abroad:
                          type: boolean
                        contacts:
                          type: array
                          description: |
                            Contatos do destinatário. Tipos utilizados pelo sistema:
                            - `EMAIL`: e-mail (pode haver mais de um)
                            - `PHONE`: telefone fixo (10 dígitos)
                            - `CELLPHONE`: celular (11 dígitos)
                          items:
                            type: object
                            required:
                              - type
                              - value
                            properties:
                              type:
                                type: string
                                enum:
                                  - EMAIL
                                  - PHONE
                                  - CELLPHONE
                                example: EMAIL
                                description: |
                                  Tipo do contato:
                                  - `EMAIL`: e-mail
                                  - `PHONE`: telefone fixo
                                  - `CELLPHONE`: celular
                              value:
                                type: string
                                example: joao@email.com
                                description: Valor do contato (e-mail ou número)
                        addresses:
                          type: array
                          items:
                            type: object
                            properties:
                              city:
                                type: string
                              state:
                                type: string
                              zip_code:
                                type: string
                              city_code:
                                oneOf:
                                  - type: string
                                  - type: number
                                  - type: "null"
                              name:
                                type: string
                                description: Nome do logradouro
                              number:
                                type: string
                              district:
                                type: string
                              complement:
                                type: string
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                  count:
                    type: integer
    post:
      tags:
        - Clientes
      summary: Criar novo cliente
      description: |
        Cria um novo cliente para recebimento de NFCom/NFSe.
        Campos opcionais podem ser enviados vazios ("") ou null quando indicado.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                code:
                  type: string
                  maxLength: 15
                  nullable: true
                company:
                  type: string
                document:
                  type: string
                  description: CPF ou CNPJ do cliente
                site:
                  type: string
                indicatorIe:
                  type: integer
                  nullable: true
                  description: Indicador IE (ver tipos aceitos)
                ie_rg:
                  type: string
                im:
                  type: string
                taxation_system:
                  type: string
                type:
                  type: string
                abroad:
                  type: boolean
                  default: false
                contacts:
                  type: array
                  description: |
                    Contatos do destinatário. Tipos utilizados pelo sistema:
                    - `EMAIL`: e-mail (pode haver mais de um)
                    - `PHONE`: telefone fixo (10 dígitos)
                    - `CELLPHONE`: celular (11 dígitos)
                  items:
                    type: object
                    required:
                      - type
                      - value
                    properties:
                      type:
                        type: string
                        enum:
                          - EMAIL
                          - PHONE
                          - CELLPHONE
                        example: EMAIL
                        description: |
                          Tipo do contato:
                          - `EMAIL`: e-mail
                          - `PHONE`: telefone fixo
                          - `CELLPHONE`: celular
                      value:
                        type: string
                        example: joao@email.com
                        description: Valor do contato (e-mail ou número)
                addresses:
                  type: array
                  items:
                    type: object
                    properties:
                      city:
                        type: string
                      state:
                        type: string
                      zip_code:
                        type: string
                      city_code:
                        nullable: true
                      address:
                        type: string
                        description: Logradouro (nome da rua)
                      number:
                        type: string
                      district:
                        type: string
                      complement:
                        type: string
              required:
                - document
      responses:
        "200":
          description: Cliente criado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                  company:
                    type: string
                  document:
                    type: string
                  code:
                    type: string
                    nullable: true
                  indicatorIe:
                    type: integer
                    nullable: true
                  ie_rg:
                    type: string
                  im:
                    type: string
                  site:
                    type: string
                  taxation_system:
                    type: string
                  type:
                    type: string
                  abroad:
                    type: boolean
                  contacts:
                    type: array
                    description: |
                      Contatos do destinatário. Tipos utilizados pelo sistema:
                      - `EMAIL`: e-mail (pode haver mais de um)
                      - `PHONE`: telefone fixo (10 dígitos)
                      - `CELLPHONE`: celular (11 dígitos)
                    items:
                      type: object
                      required:
                        - type
                        - value
                      properties:
                        type:
                          type: string
                          enum:
                            - EMAIL
                            - PHONE
                            - CELLPHONE
                          example: EMAIL
                          description: |
                            Tipo do contato:
                            - `EMAIL`: e-mail
                            - `PHONE`: telefone fixo
                            - `CELLPHONE`: celular
                        value:
                          type: string
                          example: joao@email.com
                          description: Valor do contato (e-mail ou número)
                  addresses:
                    type: array
                    items:
                      type: object
                      properties:
                        city:
                          type: string
                        state:
                          type: string
                        zip_code:
                          type: string
                        city_code:
                          oneOf:
                            - type: string
                            - type: number
                            - type: "null"
                        name:
                          type: string
                        number:
                          type: string
                        district:
                          type: string
                        complement:
                          type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
  /clients/select:
    get:
      tags:
        - Clientes
      summary: Listar clientes para seleção (combo/select)
      description: |
        Retorna uma lista simplificada de clientes para uso em componentes de seleção (id e nome/descrição).

        Útil para autocompletes e selects do frontend.
      parameters:
        - name: textFilter
          in: query
          description: Filtro de busca por nome, documento ou ID (UUID)
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Lista simplificada de clientes retornada com sucesso
          content:
            application/json:
              schema:
                type: array
                description: Lista de clientes (máximo 50 itens)
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      format: uuid
                    name:
                      type: string
                    document:
                      type: string
                    abroad:
                      type: boolean
  /clients/generate-code:
    get:
      tags:
        - Clientes
      summary: Gerar código sequencial de cliente
      description: |
        Gera e retorna o próximo código disponível para cadastro de cliente.

        Útil para preencher automaticamente o campo "code" no cadastro.
      responses:
        "200":
          description: Código gerado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  code:
                    type: string
                    example: "00012345"
  /clients/validate-code/{code}:
    get:
      tags:
        - Clientes
      summary: Validar código do cliente
      description: Verifica se o código informado já está em uso pela empresa do token.
      parameters:
        - name: code
          in: path
          required: true
          description: Código do cliente (até 15 caracteres)
          schema:
            type: string
            maxLength: 15
      responses:
        "200":
          description: Resultado da validação
          content:
            application/json:
              schema:
                type: object
                properties:
                  valid:
                    type: boolean
                    description: true se o código está disponível
                    example: true
                  exists:
                    type: boolean
                    description: true se já existe um cliente com esse código
                    example: false
        "401":
          description: Não autorizado
          content:
            application/json:
              schema: *a45
  /clients/{id}:
    get:
      tags:
        - Clientes
      summary: Obter cliente por ID
      description: |
        Retorna os dados de um cliente específico pelo ID.

        **Para Integrações:** Use para obter dados completos de um cliente específico.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do cliente (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Cliente retornado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                  company:
                    type: string
                  document:
                    type: string
                  code:
                    type: string
                    nullable: true
                  indicatorIe:
                    type: integer
                    nullable: true
                  ie_rg:
                    type: string
                  im:
                    type: string
                  site:
                    type: string
                  taxation_system:
                    type: string
                  type:
                    type: string
                  abroad:
                    type: boolean
                  contacts:
                    type: array
                    description: |
                      Contatos do destinatário. Tipos utilizados pelo sistema:
                      - `EMAIL`: e-mail (pode haver mais de um)
                      - `PHONE`: telefone fixo (10 dígitos)
                      - `CELLPHONE`: celular (11 dígitos)
                    items:
                      type: object
                      required:
                        - type
                        - value
                      properties:
                        type:
                          type: string
                          enum:
                            - EMAIL
                            - PHONE
                            - CELLPHONE
                          example: EMAIL
                          description: |
                            Tipo do contato:
                            - `EMAIL`: e-mail
                            - `PHONE`: telefone fixo
                            - `CELLPHONE`: celular
                        value:
                          type: string
                          example: joao@email.com
                          description: Valor do contato (e-mail ou número)
                  addresses:
                    type: array
                    items:
                      type: object
                      properties:
                        city:
                          type: string
                        state:
                          type: string
                        zip_code:
                          type: string
                        city_code:
                          oneOf:
                            - type: string
                            - type: number
                            - type: "null"
                        name:
                          type: string
                        number:
                          type: string
                        district:
                          type: string
                        complement:
                          type: string
                  created_at:
                    type: string
                    format: date-time
                  updated_at:
                    type: string
                    format: date-time
        "404":
          description: Cliente não encontrado
          content:
            application/json:
              schema: *a44
    put:
      tags:
        - Clientes
      summary: Atualizar cliente
      description: |
        Atualiza os dados de um cliente específico pelo ID.

        **Para Integrações:** Use para manter dados de clientes atualizados.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do cliente (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                code:
                  type: string
                  maxLength: 15
                  nullable: true
                company:
                  type: string
                document:
                  type: string
                site:
                  type: string
                indicatorIe:
                  type: integer
                  nullable: true
                ie_rg:
                  type: string
                im:
                  type: string
                taxation_system:
                  type: string
                type:
                  type: string
                abroad:
                  type: boolean
                contacts:
                  type: array
                  description: |
                    Contatos do destinatário. Tipos utilizados pelo sistema:
                    - `EMAIL`: e-mail (pode haver mais de um)
                    - `PHONE`: telefone fixo (10 dígitos)
                    - `CELLPHONE`: celular (11 dígitos)
                  items:
                    type: object
                    required:
                      - type
                      - value
                    properties:
                      type:
                        type: string
                        enum:
                          - EMAIL
                          - PHONE
                          - CELLPHONE
                        example: EMAIL
                        description: |
                          Tipo do contato:
                          - `EMAIL`: e-mail
                          - `PHONE`: telefone fixo
                          - `CELLPHONE`: celular
                      value:
                        type: string
                        example: joao@email.com
                        description: Valor do contato (e-mail ou número)
                addresses:
                  type: array
                  items:
                    type: object
                    properties:
                      city:
                        type: string
                      state:
                        type: string
                      zip_code:
                        type: string
                      city_code:
                        nullable: true
                      address:
                        type: string
                      number:
                        type: string
                      district:
                        type: string
                      complement:
                        type: string
              required:
                - document
      responses:
        "200":
          description: Cliente atualizado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                    format: uuid
                  name:
                    type: string
                  company:
                    type: string
                  document:
                    type: string
                  code:
                    type: string
                    nullable: true
                  indicatorIe:
                    type: integer
                    nullable: true
                  ie_rg:
                    type: string
                  im:
                    type: string
                  site:
                    type: string
                  taxation_system:
                    type: string
                  type:
                    type: string
                  abroad:
                    type: boolean
                  contacts:
                    type: array
                    description: |
                      Contatos do destinatário. Tipos utilizados pelo sistema:
                      - `EMAIL`: e-mail (pode haver mais de um)
                      - `PHONE`: telefone fixo (10 dígitos)
                      - `CELLPHONE`: celular (11 dígitos)
                    items:
                      type: object
                      required:
                        - type
                        - value
                      properties:
                        type:
                          type: string
                          enum:
                            - EMAIL
                            - PHONE
                            - CELLPHONE
                          example: EMAIL
                          description: |
                            Tipo do contato:
                            - `EMAIL`: e-mail
                            - `PHONE`: telefone fixo
                            - `CELLPHONE`: celular
                        value:
                          type: string
                          example: joao@email.com
                          description: Valor do contato (e-mail ou número)
                  addresses:
                    type: array
                    items:
                      type: object
                      properties:
                        city:
                          type: string
                        state:
                          type: string
                        zip_code:
                          type: string
                        city_code:
                          oneOf:
                            - type: string
                            - type: number
                            - type: "null"
                        address:
                          type: string
                        number:
                          type: string
                        district:
                          type: string
                        complement:
                          type: string
                  updated_at:
                    type: string
                    format: date-time
        "404":
          description: Cliente não encontrado
          content:
            application/json:
              schema: *a44
    delete:
      tags:
        - Clientes
      summary: Excluir cliente
      description: |
        Exclui um cliente específico pelo ID.

        ⚠️ **ATENÇÃO:** Não é possível excluir cliente que já tenha NFCom emitidas.

        **Para Integrações:** Use com cuidado, operação irreversível.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do cliente (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Cliente excluído com sucesso (retorna array vazio)
          content:
            application/json:
              schema:
                type: array
                items: {}
        "400":
          description: Cliente não pode ser excluído (tem NFCom associadas)
          content:
            application/json:
              schema: *a44
        "404":
          description: Cliente não encontrado
          content:
            application/json:
              schema: *a44
  /services:
    get:
      tags:
        - Serviços
      operationId: listServices
      summary: Listar serviços
      description: |
        Lista serviços com filtros e paginação, retornando também a contagem total.
        Resposta: { services: Service[], count: number }
      parameters:
        - name: page
          in: query
          description: Número da página (paginação)
          required: false
          schema:
            type: integer
            default: 0
        - name: rowsPerPage
          in: query
          description: Itens por página
          required: false
          schema:
            type: integer
            default: 10
        - name: columnOrder
          in: query
          description: Campo de ordenação (ex. created_at, code)
          required: false
          schema:
            type: string
        - name: order
          in: query
          description: Direção da ordenação (asc ou desc)
          required: false
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - name: filterCode
          in: query
          description: Filtro por código do serviço (match exato, case-insensitive)
          required: false
          schema:
            type: string
        - name: filterDescription
          in: query
          description: Filtro por descrição (contém, case-insensitive)
          required: false
          schema:
            type: string
        - name: filterSubscriberType
          in: query
          description: Filtro por tipo de assinante
          required: false
          schema:
            type: string
        - name: filterTypeOfUse
          in: query
          description: Filtro por tipo de uso
          required: false
          schema:
            type: string
        - name: filterModel
          in: query
          description: Filtro por modelo (ex. 62)
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Lista de serviços retornada com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  services:
                    type: array
                    items: &a46
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        code:
                          type: string
                        active:
                          type: boolean
                        model:
                          type: integer
                        subscriber_type:
                          type: string
                        type_of_use:
                          type: string
                        description:
                          type: string
                        cst:
                          type: string
                          nullable: true
                        quantity:
                          type: number
                        unity:
                          type: string
                        suggested_value:
                          type: number
                        classification:
                          type: string
                        taxation:
                          type: string
                          nullable: true
                        icmsCst:
                          type: string
                          nullable: true
                        icms_aliquot:
                          type: number
                        bc_reduction:
                          type: number
                        pisCst:
                          type: string
                          nullable: true
                        aliquot_pis:
                          type: number
                        cofinsCst:
                          type: string
                          nullable: true
                        cofins_aliquot:
                          type: number
                        fust_aliquot:
                          type: number
                        funttel_aliquot:
                          type: number
                        withheld_pis_rate:
                          type: number
                        withheld_cofins_rate:
                          type: number
                        withheld_csll_rate:
                          type: number
                        withheld_irrf_rate:
                          type: number
                        exemption:
                          type: string
                        federal_aliquot:
                          type: number
                        state_aliquot:
                          type: number
                        municipal_aliquot:
                          type: number
                        region:
                          type: string
                        service_type:
                          type: string
                        product_type:
                          type: string
                        technology:
                          type: string
                        enabled:
                          type: boolean
                        licenseType:
                          type: string
                        cfop:
                          type: string
                        customer_id:
                          type: string
                          format: uuid
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                  count:
                    type: integer
    post:
      tags:
        - Serviços
      operationId: createService
      summary: Criar novo serviço
      description: |
        Cria um novo serviço de telecomunicação para uso em NFCom.
      requestBody:
        required: true
        content:
          application/json:
            schema: &a47
              type: object
              properties:
                code:
                  type: string
                  maxLength: 60
                  description: Código do serviço (cProd)
                enabled:
                  type: boolean
                  default: true
                  description: Se o serviço está ativo
                model:
                  type: integer
                  example: 62
                  description: Modelo fiscal (62 = NFCom)
                subscriber_type:
                  type: number
                  description: Tipo de assinante (obrigatório se model ≠ 62)
                type_of_use:
                  type: number
                  description: Tipo de utilização (obrigatório se model ≠ 62)
                description:
                  type: string
                  maxLength: 120
                  description: Descrição (xProd)
                cst:
                  type: string
                  nullable: true
                cfop:
                  type: string
                  nullable: true
                quantity:
                  type: number
                unity:
                  type: string
                suggested_value:
                  type: number
                classification:
                  oneOf:
                    - type: string
                    - type: integer
                  description: Obrigatório quando model = 62
                taxation:
                  type: string
                  nullable: true
                icmsCst:
                  type: string
                  nullable: true
                  description: Obrigatório quando model = 62
                icms_aliquot:
                  type: number
                bc_reduction:
                  type: number
                  nullable: true
                icmsFcpRate:
                  type: number
                  nullable: true
                icmsFiscalBenefitCode:
                  type: string
                  maxLength: 10
                  nullable: true
                pisCst:
                  type: string
                  nullable: true
                aliquot_pis:
                  type: number
                  nullable: true
                cofinsCst:
                  type: string
                  nullable: true
                cofins_aliquot:
                  type: number
                  nullable: true
                fust_aliquot:
                  type: number
                  nullable: true
                funttel_aliquot:
                  type: number
                  nullable: true
                ibs_cbs_cst:
                  type: string
                  nullable: true
                ibs_cbs_tax_class_code:
                  type: string
                  nullable: true
                ibs_uf_rate:
                  type: number
                  nullable: true
                ibs_uf_reduction_rate:
                  type: number
                  nullable: true
                ibs_uf_effective_rate:
                  type: number
                  nullable: true
                ibs_mun_rate:
                  type: number
                  nullable: true
                ibs_mun_reduction_rate:
                  type: number
                  nullable: true
                ibs_mun_effective_rate:
                  type: number
                  nullable: true
                cbs_rate:
                  type: number
                  nullable: true
                cbs_reduction_rate:
                  type: number
                  nullable: true
                cbs_effective_rate:
                  type: number
                  nullable: true
                withheld_pis_rate:
                  type: number
                  nullable: true
                withheld_cofins_rate:
                  type: number
                  nullable: true
                withheld_csll_rate:
                  type: number
                  nullable: true
                withheld_irrf_rate:
                  type: number
                  nullable: true
                exemption:
                  type: string
                federal_aliquot:
                  type: number
                state_aliquot:
                  type: number
                municipal_aliquot:
                  type: number
                region:
                  type: string
                service_type:
                  type: string
                product_type:
                  type: string
                technology:
                  type: string
                licenseType:
                  type: string
                interstateAliquots:
                  type: array
                  items:
                    type: object
                    required:
                      - state
                    properties:
                      state:
                        type: string
                        minLength: 2
                        maxLength: 2
                      cst:
                        type: string
                        nullable: true
                      icms:
                        type: number
                        nullable: true
                      bcReductionAliquot:
                        type: number
                        nullable: true
                      fcpRate:
                        type: number
                        nullable: true
                      fiscalBenefitCode:
                        type: string
                        maxLength: 10
                        nullable: true
              required:
                - code
                - model
                - description
      responses:
        "200":
          description: Serviço criado com sucesso
          content:
            application/json:
              schema: *a46
  /services/select:
    get:
      tags:
        - Serviços
      operationId: listServicesByModel
      summary: Listar serviços por modelo (select)
      description: Retorna lista simplificada de serviços habilitados filtrados por modelo (ex. 62).
      parameters:
        - name: model
          in: query
          required: true
          description: Modelo de documento (ex. 62)
          schema:
            type: integer
      responses:
        "200":
          description: Lista de serviços retornada com sucesso
          content:
            application/json:
              schema:
                type: array
                items: *a46
        "404":
          description: Serviços não encontrados
          content:
            application/json:
              schema: *a44
  /services/check-code/{code}:
    get:
      tags:
        - Serviços
      operationId: checkServiceCode
      summary: Verificar existência de serviço por código
      description: Verifica se existe um serviço com o código informado para a empresa do token.
      parameters:
        - name: code
          in: path
          required: true
          description: Código do serviço
          schema:
            type: string
      responses:
        "200":
          description: Resultado da verificação
          content:
            application/json:
              schema:
                type: object
                properties:
                  exists:
                    type: boolean
                    example: true
                  service:
                    oneOf:
                      - *a46
                      - type: "null"
  /services/{id}:
    get:
      tags:
        - Serviços
      operationId: getServiceById
      summary: Obter serviço por ID
      description: Retorna os dados de um serviço específico pelo ID.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do serviço (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Serviço retornado com sucesso
          content:
            application/json:
              schema: *a46
        "404":
          description: Serviço não encontrado
          content:
            application/json:
              schema: *a44
    put:
      tags:
        - Serviços
      operationId: updateService
      summary: Atualizar serviço
      description: Atualiza os dados de um serviço específico pelo ID.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do serviço (UUID)
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema: *a47
      responses:
        "200":
          description: Serviço atualizado com sucesso
          content:
            application/json:
              schema: *a46
        "404":
          description: Serviço não encontrado
          content:
            application/json:
              schema: *a44
    delete:
      tags:
        - Serviços
      operationId: deleteService
      summary: Excluir serviço
      description: Exclui um serviço específico pelo ID; retorna array vazio.
      parameters:
        - name: id
          in: path
          required: true
          description: ID do serviço (UUID)
          schema:
            type: string
            format: uuid
      responses:
        "200":
          description: Serviço excluído com sucesso (array vazio)
          content:
            application/json:
              schema:
                type: array
                items: {}
        "404":
          description: Serviço não encontrado
          content:
            application/json:
              schema: *a44
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Token de integração gerado no painel TelcomNFe
        (Configurações → Integração API).

        Exemplo: `Authorization: Bearer eyJhbGciOi...`
