{
  "openapi": "3.0.4",
  "info": {
    "title": "API de Integração Commercio",
    "description": "API pública de integração do ERP Commercio: clientes, ordens de serviço (e receita óptica), vendas com pagamentos,\ndevoluções, financeiro (contas a receber e cobrança) e as áreas com escrita: e-commerce e dilab (O.S. de laboratório).\n\n**Guia completo (texto, público):** [/api/integracao/llms.txt](/api/integracao/llms.txt) — também em `/llms.txt`.\n\n## Como começar\n1. Peça um token: `POST /api/connect/token` com `grant_type=client_credentials`, `client_id` e `client_secret`\n   (`Content-Type: application/x-www-form-urlencoded`). O token vale 1 hora.\n2. Envie-o em `Authorization: Bearer <token>` (botão **Authorize** acima).\n3. `GET /api/integracao/v1/empresas` lista as filiais liberadas; o `cnpj` delas é o `empresaCnpj` das demais rotas.\n4. `GET /api/integracao/v1/ping?empresaCnpj=<cnpj>` confere token e empresa.\n\nO token (JWS RS256) carrega os **escopos por área** e a lista de empresas (`allowed_cnpjs`); empresa fora dela =\n403 `EMPRESA_NAO_AUTORIZADA`. Descoberta OAuth: `/.well-known/openid-configuration` (chaves em `/api/.well-known/jwks`,\ncom rotação — ao ver um `kid` desconhecido, baixe o JWKS de novo).\n\n## Convenções\n- Listas: `{ data, nextCursor }`. Repita a chamada com `cursor=<nextCursor>` e os MESMOS filtros; fim = `nextCursor`\n  ausente. `limite`: padrão 100, máximo 1000.\n- Limite de uso: 120 requisições por minuto por credencial; acima = 429 `RATE_LIMITED` com `Retry-After`.\n- JSON em camelCase; datas `YYYY-MM-DD`; data e hora em ISO 8601 sem fuso (horário da instalação).\n- Campos vazios são **omitidos**, nunca `null` — exceto `cliente: null` (cliente não identificado).\n- Vocabulários (situacao, tipo…) aceitam qualquer caixa na entrada.\n\n## Erros\nRFC 9457 (`application/problem+json`) com `code` estável e `traceId` (informe-o à Dataweb ao reportar um problema).\n400 `INVALID_PARAMS` | `INVALID_LIMIT` | `INVALID_CURSOR` | `ORDEM_SERVICO_INVALIDA` (com a lista `erros`) |\n`OTICA_NAO_ENCONTRADA` | `OTICA_NEGATIVADA` | `LENTE_GENERICA_NAO_CONFIGURADA` · 401 `NAO_AUTENTICADO` | `CREDENCIAL_REVOGADA` ·\n403 `ESCOPO_INSUFICIENTE` | `EMPRESA_NAO_AUTORIZADA` · 404 `NOT_FOUND` · 409 `CONFLICT` | `PEDIDO_DUPLICADO` |\n`PEDIDO_JA_ACEITO` | `PEDIDO_EM_PRODUCAO` | `PEDIDO_CANCELADO` | `PEDIDO_REJEITADO` | `ORDEM_SERVICO_DUPLICADA` ·\n429 `RATE_LIMITED` · 500 `INTERNAL_ERROR` ·\n502 `GATEWAY_INDISPONIVEL` · 503 `GATEWAY_OCUPADO`.\n\n## LGPD\nTodo dado de pessoa traz `consentimentoLgpd`; contatos e endereço de quem recusou saem omitidos.",
    "version": "1.12"
  },
  "paths": {
    "/api/integracao/v1/clientes": {
      "get": {
        "tags": [
          "Clientes"
        ],
        "summary": "Base cadastral de clientes da empresa, paginada por cursor.\r\n`celular` sai normalizado para WhatsApp (55DDD9XXXXXXXX) ou nulo.\r\nCom `cpf` (pessoa física) OU `cnpj` (pessoa jurídica): localiza o cadastro do cliente\r\npelo documento — os dois juntos são 400 (snapshot só encontra ativos; para desativados,\r\ncombine com `alteradoEm[gte]`).\r\nCom `alteradoEm[gte]` (sync incremental): retorna só linhas alteradas/incluídas a\r\npartir do watermark, INCLUINDO clientes desativados (`ativo: false`). Use `>=` com\r\nmargem de segurança e deduplique por `cpf`/`cnpj` (cadastros sem documento não têm\r\nchave natural) — ver o contrato.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cnpj` (os dois juntos = 400). Busca exata; sem `alteradoEm[gte]` só encontra cliente ativo.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cpf` (os dois juntos = 400).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "consentimentoLgpd",
            "in": "query",
            "description": "Filtra pelo consentimento LGPD: naoEnviado | naoRespondido | aguardando | aceitou | recusou (qualquer caixa); outro valor = 400.",
            "schema": {
              "enum": [
                "naoEnviado",
                "naoRespondido",
                "aguardando",
                "aceitou",
                "recusou"
              ],
              "type": "string"
            }
          },
          {
            "name": "alteradoEm[gte]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradoEm[gt]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradosDesde",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `alteradoEm[gte]`. Não misture com `alteradoEm[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.clientes:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/clientes/aniversariantes": {
      "get": {
        "tags": [
          "Clientes"
        ],
        "summary": "Aniversariantes do mês (e opcionalmente do dia). Janela que atravessa a virada\r\ndo mês = duas chamadas — por desenho, para o filtro nunca sair silenciosamente errado.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "mes",
            "in": "query",
            "description": "Mês de aniversário, 1 a 12 (padrão: o mês atual).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "dia",
            "in": "query",
            "description": "Dia de aniversário, 1 a 31 (opcional). Janela que cruza o mês = duas chamadas.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "consentimentoLgpd",
            "in": "query",
            "description": "Filtra pelo consentimento LGPD: naoEnviado | naoRespondido | aguardando | aceitou | recusou (qualquer caixa); outro valor = 400.",
            "schema": {
              "enum": [
                "naoEnviado",
                "naoRespondido",
                "aguardando",
                "aceitou",
                "recusou"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraClienteLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.clientes:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/cobranca/lancamentos": {
      "get": {
        "tags": [
          "Cobranca"
        ],
        "summary": "Vencidos (cobráveis) de todos os clientes das empresas autorizadas.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ(s) das empresas credoras, repetível e opcional — padrão: todas as empresas liberadas no token. Fora da lista = 403 EMPRESA_NAO_AUTORIZADA.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "antecedencia",
            "in": "query",
            "description": "Dias à frente além dos vencidos: 0 (padrão) só vencidos; 1 inclui os que\r\n            vencem hoje; 2 os que vencem amanhã; … até 7. Os itens da janela saem com `situacao = emAberto`.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.cobranca:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1": {
      "get": {
        "tags": [
          "Descoberta"
        ],
        "summary": "Raiz autodescritiva: nome, versão, escopos e links de descoberta.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRaizLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRaizLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiRaizLeitura"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [ ]
          }
        ]
      }
    },
    "/api/integracao/v1/version": {
      "get": {
        "tags": [
          "Descoberta"
        ],
        "summary": "Versão da SUPERFÍCIE da API (nome + versão semântica das áreas/escopos). Runtime e\r\n            horário de início do processo são diagnóstico de infraestrutura, não contrato — ficam de fora.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ApiVersaoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiVersaoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiVersaoLeitura"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [ ]
          }
        ]
      }
    },
    "/api/integracao/llms.txt": {
      "get": {
        "tags": [
          "Descoberta"
        ],
        "summary": "Guia legível por agentes (llms.txt) em `/api/integracao/llms.txt` — fora do prefixo\r\nde versão porque descreve a API como um todo. Rota absoluta para escapar do `v1`.\r\nPÚBLICO (sem token), como o `swagger.json`: é só documentação, não serve dado, e precisa\r\nabrir no navegador de quem ainda está começando a integração (v1.6).",
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/integracao/v1/devolucoes": {
      "get": {
        "tags": [
          "Devolucoes"
        ],
        "summary": "Devoluções encerradas recebidas pela empresa, com itens, paginadas por cursor. Um recorte é\r\nobrigatório, combináveis: o cliente (`cpf` OU `cnpj`), o período de emissão DA DEVOLUÇÃO\r\n(`dataEmissao[gte]` + `dataEmissao[lte]`, no máximo 92 dias) e a venda de origem (`codVenda`).",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cnpj` (os dois juntos = 400).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cpf` (os dois juntos = 400).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "codVenda",
            "in": "query",
            "description": "Só as devoluções desta venda de origem (o `codVenda` de /vendas). Ao menos um recorte: cliente, período ou codVenda — combináveis.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataEmissao[gte]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): a partir de (≥, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[gt]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): depois de (>, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[lte]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): até (≤, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[lt]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): antes de (<, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataInicial",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEmissao[gte]`. Não misture com `dataEmissao[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataFinal",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEmissao[lte]`. Não misture com `dataEmissao[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraDevolucaoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraDevolucaoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraDevolucaoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.vendas:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/devolucoes/{codDevolucao}": {
      "get": {
        "tags": [
          "Devolucoes"
        ],
        "summary": "Leitura pontual de uma devolução recebida pela empresa; 404 quando não existe nela.",
        "parameters": [
          {
            "name": "codDevolucao",
            "in": "path",
            "description": "Identificador da devolução (o `codDevolucao` de /devolucoes). 404 quando não existe nesta empresa.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/DevolucaoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DevolucaoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/DevolucaoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.vendas:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/ordens-servico": {
      "post": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Envia uma O.S. de laboratório. Idempotente por ótica e `idPedidoOtica`: nova = 201 com a O.S.; reenvio = 200 com a\r\nO.S. já gravada (mesmo recusada — para corrigir, envie outro `idPedidoOtica`). Inválida = 400 ORDEM_SERVICO_INVALIDA\r\ncom TODOS os problemas na lista `erros`.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "A O.S.: idPedidoOtica, oticaCnpj, receita (descrição da lente por olho), armação, parâmetros, paciente, médico, vendedor e serviços.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:write"
            ]
          }
        ]
      },
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "As O.S. enviadas pelo integrador ao laboratório, inclusive as recusadas, paginadas (keyset) na ordem de recebimento.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "oticaCnpj",
            "in": "query",
            "description": "Só as O.S. desta ótica (CNPJ com ou sem máscara).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "idPedidoOtica",
            "in": "query",
            "description": "Só a O.S. com este identificador.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "situacao",
            "in": "query",
            "description": "Só as O.S. nesta situação: aberta, aprovada, encerrada, cancelada ou recusada.",
            "schema": {
              "enum": [
                "orcamento",
                "aberta",
                "pronta",
                "entregue"
              ],
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataInclusao[gte]",
            "in": "query",
            "description": "Filtro por data e hora em que a O.S. foi recebida (dataInclusao): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dataInclusao[gt]",
            "in": "query",
            "description": "Filtro por data e hora em que a O.S. foi recebida (dataInclusao): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dataInclusao[lte]",
            "in": "query",
            "description": "Filtro por data e hora em que a O.S. foi recebida (dataInclusao): até (≤, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dataInclusao[lt]",
            "in": "query",
            "description": "Filtro por data e hora em que a O.S. foi recebida (dataInclusao): antes de (<, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabResumo"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabResumo"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabResumo"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/ordens-servico/validar": {
      "post": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Valida a O.S. SEM gravar: o mesmo corpo e as mesmas validações do POST. 204 = seria aceita; senão o mesmo 400\r\n(ORDEM_SERVICO_INVALIDA com a lista `erros`) ou 409 (idPedidoOtica já usado) que o POST daria.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "A O.S., como no POST.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/OrdemServicoLab"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No Content"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:write"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/ordens-servico/{numero}": {
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "A O.S. como está no laboratório (a lente já trocada aparece com a descrição real). Recusada: o que foi enviado,\r\ncom `situacao` recusada e a `recusa` (data e motivo).",
        "parameters": [
          {
            "name": "numero",
            "in": "path",
            "description": "Número da O.S. (o `numero` devolvido no POST). Cada integrador só vê as próprias O.S.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLab"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/ordens-servico/{numero}/status": {
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Situação da O.S. (aberta, aprovada, encerrada, cancelada ou recusada), a recusa e as etapas da produção.",
        "parameters": [
          {
            "name": "numero",
            "in": "path",
            "description": "Número da O.S. (o `numero` devolvido no POST). Cada integrador só vê as próprias O.S.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int64"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLabStatus"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLabStatus"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLabStatus"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/materiais": {
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Todos os materiais da armação do laboratório (o `codigo` vai em `armacao.material`), sem paginação.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabMaterial"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabMaterial"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabMaterial"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:write"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/formatos-aro": {
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Todos os formatos do aro ativos do laboratório, com a imagem (PNG em base64) — o `codigo` vai em `armacao.formatoAro`; sem paginação.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabFormatoAro"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabFormatoAro"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabFormatoAro"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:write"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/dilab/servicos": {
      "get": {
        "tags": [
          "DilabOrdensServico"
        ],
        "summary": "Os serviços que a O.S. pode levar (o `codigo` vai em `servicos[].codigo`), paginados por código.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ do laboratório (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "descricao",
            "in": "query",
            "description": "Só os serviços cuja descrição contém este texto (sem diferenciar maiúsculas).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabServicoDisponivel"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabServicoDisponivel"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLabServicoDisponivel"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:write"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.dilab.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/pedidos": {
      "post": {
        "tags": [
          "EcommercePedidos"
        ],
        "summary": "Grava um pedido de e-commerce na loja. Idempotente por `numeroPedido`: novo = 201; reenvio do mesmo pedido = 200 com o pedido gravado; número já recebido por outra integração = 409 PEDIDO_DUPLICADO.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "O pedido: numeroPedido (1 a 30 caracteres [A-Za-z0-9._-], chave de idempotência), consumidor, itens (SKU), pagamentos (a soma deve bater com o total).",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PedidoEcommerce"
              }
            },
            "text/json": {
              "schema": {
                "$ref": "#/components/schemas/PedidoEcommerce"
              }
            },
            "application/*+json": {
              "schema": {
                "$ref": "#/components/schemas/PedidoEcommerce"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              }
            }
          },
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.pedidos:write"
            ]
          }
        ]
      },
      "get": {
        "tags": [
          "EcommercePedidos"
        ],
        "summary": "Pedidos do integrador na empresa, paginados (keyset). `alteradoEm[gte]` = watermark pela última\r\nalteração da O.S. — aceite (venda), NF-e, despacho e entrega contam como alteração; cancelado/rejeitado\r\nentra pela data em que foi recebido.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "alteradoEm[gte]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradoEm[gt]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradosDesde",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `alteradoEm[gte]`. Não misture com `alteradoEm[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraPedidoEcommerceResumo"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraPedidoEcommerceResumo"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraPedidoEcommerceResumo"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.pedidos:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/pedidos/{numeroPedido}": {
      "get": {
        "tags": [
          "EcommercePedidos"
        ],
        "summary": "Situação e detalhe de um pedido de e-commerce (recebido, aceito, emitidaNf, despachado, entregue, cancelado, rejeitado), com venda, nota e expedição quando houver.",
        "parameters": [
          {
            "name": "numeroPedido",
            "in": "path",
            "description": "Número do pedido na plataforma (o enviado no POST). Cada integrador só vê os próprios pedidos.",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceDetalhe"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.pedidos:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/pedidos/{numeroPedido}/cancelar": {
      "post": {
        "tags": [
          "EcommercePedidos"
        ],
        "summary": "Cancela o pedido enquanto a loja não gerou a venda (aceite). Depois disso, 409\r\n`PEDIDO_JA_ACEITO` — devolução é tratada com a loja. Com o laboratório já trabalhando na O.S.\r\n(recebida no laboratório externo ou O.S. de laboratório já alterada), 409 `PEDIDO_EM_PRODUCAO`.\r\nO pedido continua consultável como\r\n`cancelado`; a reserva de estoque feita no recebimento é estornada.",
        "parameters": [
          {
            "name": "numeroPedido",
            "in": "path",
            "description": "Número do pedido na plataforma. Só enquanto a loja não aceitou (409 PEDIDO_JA_ACEITO depois disso) e o laboratório não começou (409 PEDIDO_EM_PRODUCAO).",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceCancelado"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceCancelado"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoEcommerceCancelado"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.pedidos:write"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/produtos": {
      "get": {
        "tags": [
          "EcommerceProdutos"
        ],
        "summary": "Catálogo incremental do tenant (produtos ativos com SKU), paginado — keyset pela chave textual\r\n`codItem`. `alteradoEm[gte]` é OBRIGATÓRIO: sem delta seria um dump do catálogo inteiro\r\n(para a carga inicial, use uma data antiga).",
        "parameters": [
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "alteradoEm[gte]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental). Obrigatório: informe `alteradoEm[gte]` ou `alteradoEm[gt]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradoEm[gt]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental). Obrigatório: informe `alteradoEm[gte]` ou `alteradoEm[gt]`.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradosDesde",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `alteradoEm[gte]`. Não misture com `alteradoEm[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraProdutoEcommerce"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraProdutoEcommerce"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraProdutoEcommerce"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.produtos:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/produtos/{id}": {
      "get": {
        "tags": [
          "EcommerceProdutos"
        ],
        "summary": "Um produto do catálogo pelo código externo (SKU) — o `id` usado nos itens do pedido.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Código externo (SKU) do produto — o `id` usado nos itens do pedido.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProdutoEcommerce"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProdutoEcommerce"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProdutoEcommerce"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.produtos:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ecommerce/estoque": {
      "get": {
        "tags": [
          "EcommerceProdutos"
        ],
        "summary": "Saldo da PRATELEIRA (local 1, o disponível para venda) por produto, paginado pelo código do item.\r\nCarga inicial (sem `alteradoEm[gte]`): só produtos com saldo diferente de zero — o que não vem\r\nestá zerado. Sync incremental (`alteradoEm[gte]`): todo saldo alterado, inclusive os que zeraram.\r\nSaldo negativo sai como está (trate como zero).",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "alteradoEm[gte]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradoEm[gt]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradosDesde",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `alteradoEm[gte]`. Não misture com `alteradoEm[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEstoqueEcommerce"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEstoqueEcommerce"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEstoqueEcommerce"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ecommerce.estoque:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/empresas": {
      "get": {
        "tags": [
          "Empresas"
        ],
        "summary": "Empresas/filiais deste ambiente — o ponto de partida do integrador: o `cnpj`\r\nretornado é o valor a usar em `empresaCnpj` nos demais endpoints. Coleção limitada\r\npelo domínio; mesmo envelope das listas, sem cursor (nextCursor sempre ausente).",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEmpresaLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEmpresaLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraEmpresaLeitura"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [ ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/clientes": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Clientes (por `cpf`/`cnpj`, repetíveis) com vínculo financeiro com a empresa credora — confirma quem pode ser consultado nesta área.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF(s) do cliente, repetível (`cpf=…&cpf=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total; documento válido mas desconhecido é só omitido.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ(s) do cliente, repetível (`cnpj=…&cnpj=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraFinanceiroClienteLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraFinanceiroClienteLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraFinanceiroClienteLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/lancamentos": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Parcelas de contas a receber dos clientes informados (`cpf`/`cnpj`, repetíveis), com a situação calculada no servidor (pago, pagoEmAtraso, emAberto, vencido). Paginado por cursor.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF(s) do cliente, repetível (`cpf=…&cpf=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total; documento válido mas desconhecido é só omitido.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ(s) do cliente, repetível (`cnpj=…&cnpj=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraLancamentoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/notas-fiscais": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Notas fiscais autorizadas (NF-e, NFC-e, NFS-e) dos clientes informados (`cpf`/`cnpj`, repetíveis). Paginado por cursor; o download usa o `id` opaco.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF(s) do cliente, repetível (`cpf=…&cpf=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total; documento válido mas desconhecido é só omitido.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ(s) do cliente, repetível (`cnpj=…&cnpj=…`), com ou sem máscara. Ao menos um `cpf` ou `cnpj`; até 100 documentos no total.",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraNotaFiscalLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraNotaFiscalLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraNotaFiscalLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/notas-fiscais/{id}/xml": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "XML da nota fiscal (`id` opaco de /financeiro/notas-fiscais). Com ETag/304; 404 quando a nota não existe ou não pertence ao escopo.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador opaco da nota (o `id` de /financeiro/notas-fiscais).",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CPF(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CNPJ(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "antecedencia",
            "in": "query",
            "description": "Cobrança: inclui também as parcelas que vencem nos próximos dias (0 = só vencidas, 1 = + hoje, 2 = + amanhã…; 0 a 7, padrão 0). Com o escopo de cobrança e sem cpf/cnpj, só o que a cobrança lista é acessível.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "304": {
            "description": "Not Modified"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.financeiro.cobranca:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/notas-fiscais/{id}/pdf": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "PDF (DANFE/DANFSE) da nota fiscal, renderizado pelo ERP. Com ETag/304; 502/503 quando o gerador está indisponível ou ocupado.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador opaco da nota (o `id` de /financeiro/notas-fiscais).",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CPF(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CNPJ(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "antecedencia",
            "in": "query",
            "description": "Cobrança: inclui também as parcelas que vencem nos próximos dias (0 = só vencidas, 1 = + hoje, 2 = + amanhã…; 0 a 7, padrão 0). Com o escopo de cobrança e sem cpf/cnpj, só o que a cobrança lista é acessível.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "304": {
            "description": "Not Modified"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.financeiro.cobranca:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/financeiro/lancamentos/{id}/boleto": {
      "get": {
        "tags": [
          "Financeiro"
        ],
        "summary": "Segunda via do boleto de uma parcela (`id` de /financeiro/lancamentos), em PDF. 409 quando a parcela está paga ou não tem boleto registrado.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "description": "Identificador da parcela (o `id` de /financeiro/lancamentos).",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CPF(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "Visão por documento (escopo contas-receber): CNPJ(s) do dono, repetível. Com a credencial de cobrança, não informe (403 ESCOPO_INSUFICIENTE).",
            "schema": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          {
            "name": "antecedencia",
            "in": "query",
            "description": "Cobrança: inclui também as parcelas que vencem nos próximos dias (0 = só vencidas, 1 = + hoje, 2 = + amanhã…; 0 a 7, padrão 0). Com o escopo de cobrança e sem cpf/cnpj, só o que a cobrança lista é acessível.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "409": {
            "description": "Conflict",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "502": {
            "description": "Bad Gateway",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "503": {
            "description": "Service Unavailable",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.financeiro.contas-receber:read"
            ]
          },
          {
            "oauth2": [
              "commercio.integracao.financeiro.cobranca:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ordens-servico/{numero}": {
      "get": {
        "tags": [
          "OrdensServico"
        ],
        "summary": "Status de uma OS pelo número — escopado pela empresa (`numeroOrdemServico` só é\r\núnico por empresa). Com `cpf` informado, confirma que a OS pertence ao cliente;\r\ndivergência responde 404 (mesma resposta de OS inexistente, contra enumeração).\r\nInclui histórico de etapas, itens e ordens de compra.",
        "parameters": [
          {
            "name": "numero",
            "in": "path",
            "description": "Número da O.S.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente para conferência (opcional): se não for o da O.S., a resposta é 404 — a mesma de O.S. inexistente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/OrdemServicoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ordens-servico/{numero}/receita": {
      "get": {
        "tags": [
          "OrdensServico"
        ],
        "summary": "Receita óptica da OS — graus, medidas e LINKS das imagens (os bytes saem pelo\r\nendpoint binário abaixo). Mesmo escopo/guardas da consulta da OS; a ORDEM dos\r\nguardas importa: um `cpf` divergente responde a MESMA mensagem de OS inexistente e\r\nnunca revela se a receita existe. OS sem receita = 404 com mensagem própria\r\n(use `temReceita` da consulta/listagem para saber de antemão).",
        "parameters": [
          {
            "name": "numero",
            "in": "path",
            "description": "Número da O.S.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente para conferência (opcional): se não for o da O.S., a resposta é 404 — a mesma de O.S. inexistente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ReceitaLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceitaLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceitaLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ordens-servico.receita:read",
              "commercio.integracao.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ordens-servico/{numero}/receita/imagens/{qual}": {
      "get": {
        "tags": [
          "OrdensServico"
        ],
        "summary": "Bytes de UMA imagem da receita, como HTTP de verdade: Content-Type real (magic\r\nbytes), ETag/304 para o consumidor revalidar de graça, e 302 quando a instalação\r\nguarda a foto num serviço de imagens externo. Mesmos guardas da receita.",
        "parameters": [
          {
            "name": "numero",
            "in": "path",
            "description": "Número da O.S.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "qual",
            "in": "path",
            "description": "Qual imagem: receita | armacao | armacaoAntiga; outro valor = 400.",
            "required": true,
            "schema": {
              "enum": [
                "receita",
                "armacao",
                "armacaoAntiga"
              ],
              "type": "string"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente para conferência (opcional): se não for o da O.S., a resposta é 404 — a mesma de O.S. inexistente.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "302": {
            "description": "Found"
          },
          "304": {
            "description": "Not Modified"
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ordens-servico.receita:read",
              "commercio.integracao.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ordens-servico": {
      "get": {
        "tags": [
          "OrdensServico"
        ],
        "summary": "Listagem única de OS da empresa, paginada, sem histórico — todos os filtros\r\ncombináveis (`cpf`, `etapa`, `situacao`, `alteradoEm[gte]`, `dataEntrega[gte]`+`dataEntrega[lte]`).\r\nSem `situacao`, orçamentos ficam de fora; `situacao=orcamento` os seleciona.\r\n`alteradoEm[gte]` = polling de mudanças (toda troca de etapa conta como alteração).\r\n`incluir=itens,ordensCompra` expande o payload e NÃO participa do cursor: muda a\r\nforma da resposta, nunca o conjunto de linhas.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "Só as O.S. deste cliente (CPF, com ou sem máscara); inválido = 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "etapa",
            "in": "query",
            "description": "Só as O.S. cuja etapa ATUAL tem este código (inteiro ≥ 0; O.S. sem registro de etapa = 0).",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "situacao",
            "in": "query",
            "description": "orcamento | aberta | pronta | entregue (derivada, independente de `etapa`). Sem ela, orçamentos ficam de fora.",
            "schema": {
              "enum": [
                "orcamento",
                "aberta",
                "pronta",
                "entregue"
              ],
              "type": "string"
            }
          },
          {
            "name": "incluir",
            "in": "query",
            "description": "Expansões opcionais, separadas por vírgula: itens, ordensCompra. Não entra no cursor; outro valor = 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "alteradoEm[gte]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): a partir de (≥, inclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradoEm[gt]",
            "in": "query",
            "description": "Filtro por data e hora da última alteração (alteradoEm): depois de (>, exclusive) este valor, data (YYYY-MM-DD) ou data e hora ISO 8601 (YYYY-MM-DDTHH:MM:SS). Só limite inferior (polling incremental).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "alteradosDesde",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `alteradoEm[gte]`. Não misture com `alteradoEm[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "dataEntrega[gte]",
            "in": "query",
            "description": "Filtro por data de entrega ao cliente (dataEntrega): a partir de (≥, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEntrega[gt]",
            "in": "query",
            "description": "Filtro por data de entrega ao cliente (dataEntrega): depois de (>, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEntrega[lte]",
            "in": "query",
            "description": "Filtro por data de entrega ao cliente (dataEntrega): até (≤, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEntrega[lt]",
            "in": "query",
            "description": "Filtro por data de entrega ao cliente (dataEntrega): antes de (<, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "entregaDe",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEntrega[gte]`. Não misture com `dataEntrega[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "entregaAte",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEntrega[lte]`. Não misture com `dataEntrega[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraOrdemServicoLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.ordens-servico:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/ping": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Verificação de conectividade do integrador: exige token válido com escopo de leitura.\r\nCom `empresaCnpj` informado, também confirma que a empresa existe neste ambiente;\r\nvazio conta como ausente (a mesma regra das demais rotas).",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "Opcional: com ele o ping também confere a empresa (403 EMPRESA_NAO_AUTORIZADA / 400 se não cadastrada).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PingLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PingLeitura"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [ ]
          }
        ]
      }
    },
    "/api/integracao/v1/vendas": {
      "get": {
        "tags": [
          "Vendas"
        ],
        "summary": "VENDAS encerradas da empresa (movimento de venda — não pedidos, ordens de compra nem notas de\r\nentrada/devolução), com itens, paginadas por cursor. Um recorte é obrigatório: o cliente\r\n(`cpf` OU `cnpj` — os dois juntos são 400) e/ou o período de emissão (`dataEmissao[gte]` +\r\n`dataEmissao[lte]`, no máximo 92 dias). Só por período, a lista inclui as vendas a consumidor NÃO identificado\r\n(ex.: NFC-e), com `\"cliente\": null` explícito. Cliente sem vendas (ou inexistente) responde\r\npágina vazia — 200 com data: []. `incluir=pagamentos,devolucoes` expande o payload e NÃO\r\nparticipa do cursor: muda a forma da resposta, nunca o conjunto de linhas.",
        "parameters": [
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cpf",
            "in": "query",
            "description": "CPF do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cnpj` (os dois juntos = 400).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cnpj",
            "in": "query",
            "description": "CNPJ do cliente (com ou sem máscara); inválido = 400 INVALID_PARAMS. Não combine com `cpf` (os dois juntos = 400).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "incluir",
            "in": "query",
            "description": "Expansões opcionais, separadas por vírgula: pagamentos (fatura e parcelas), devolucoes. Não entra no cursor; outro valor = 400.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limite",
            "in": "query",
            "description": "Tamanho da página: padrão 100, máximo 1000 (acima disso é reduzido para 1000, não é erro); zero ou negativo = 400 INVALID_LIMIT.",
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "description": "O `nextCursor` da página anterior, repetindo os MESMOS filtros. Opaco — não interprete nem guarde por muito tempo; inválido ou com filtros diferentes = 400 INVALID_CURSOR. Fim da lista = `nextCursor` ausente.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dataEmissao[gte]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): a partir de (≥, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[gt]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): depois de (>, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[lte]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): até (≤, inclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataEmissao[lt]",
            "in": "query",
            "description": "Filtro por data de emissão (dataEmissao): antes de (<, exclusive) este valor, YYYY-MM-DD (dia inteiro). Período fechado: informe o início (gte ou gt) e o fim (lte ou lt) juntos, no máximo 92 dias.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataInicial",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEmissao[gte]`. Não misture com `dataEmissao[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "dataFinal",
            "in": "query",
            "description": "Descontinuado (nome anterior à v1.8): equivale a `dataEmissao[lte]`. Não misture com `dataEmissao[...]` (400).",
            "deprecated": true,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraVendaLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraVendaLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginaLeituraVendaLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.vendas:read"
            ]
          }
        ]
      }
    },
    "/api/integracao/v1/vendas/{codVenda}": {
      "get": {
        "tags": [
          "Vendas"
        ],
        "summary": "Leitura pontual de uma venda da empresa, no mesmo formato da lista (aceita o mesmo `incluir`).\r\n404 quando a venda não existe NESTA empresa — inclusive a venda CANCELADA, que o ERP exclui.",
        "parameters": [
          {
            "name": "codVenda",
            "in": "path",
            "description": "Identificador da venda (o `codVenda` de /vendas). 404 quando não existe nesta empresa — inclusive a venda cancelada, que o ERP exclui.",
            "required": true,
            "schema": {
              "type": "integer",
              "format": "int32"
            }
          },
          {
            "name": "empresaCnpj",
            "in": "query",
            "description": "CNPJ da filial (com ou sem máscara), obrigatório. Deve estar na lista de empresas do token — fora dela = 403 EMPRESA_NAO_AUTORIZADA; inválido ou não cadastrado = 400. As filiais saem em GET /empresas.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "incluir",
            "in": "query",
            "description": "Expansões opcionais, separadas por vírgula: pagamentos, devolucoes; outro valor = 400.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/VendaLeitura"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendaLeitura"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/VendaLeitura"
                }
              }
            }
          },
          "400": {
            "description": "Bad Request",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "404": {
            "description": "Not Found",
            "content": {
              "text/plain": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              },
              "text/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "401": {
            "description": "Sem token, token inválido ou expirado (`NAO_AUTENTICADO`) ou credencial revogada (`CREDENCIAL_REVOGADA`). Traz `WWW-Authenticate: Bearer`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "403": {
            "description": "O token não tem o escopo exigido (`ESCOPO_INSUFICIENTE`) ou a empresa está fora da lista do token (`EMPRESA_NAO_AUTORIZADA`).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido (`RATE_LIMITED`); aguarde o `Retry-After`.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/ProblemDetails"
                }
              }
            }
          }
        },
        "security": [
          {
            "oauth2": [
              "commercio.integracao.vendas:read"
            ]
          }
        ]
      }
    }
  },
  "components": {
    "schemas": {
      "ApiRaizLeitura": {
        "required": [
          "descricao",
          "escopos",
          "links",
          "nome",
          "versao"
        ],
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome da API.",
            "nullable": true
          },
          "versao": {
            "type": "string",
            "description": "Versão da superfície da API (ex.: `1.7`), independente do `v1` da rota.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição curta da API.",
            "nullable": true
          },
          "escopos": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Escopos (áreas) conhecidos desta versão — os que um token pode conter.",
            "nullable": true
          },
          "links": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Links de descoberta (self, version, openapi, llmsTxt, ping).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ApiVersaoLeitura": {
        "required": [
          "nome",
          "versao"
        ],
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome da API.",
            "nullable": true
          },
          "versao": {
            "type": "string",
            "description": "Versão da superfície da API (ex.: `1.7`), independente do `v1` da rota.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "BandeiraLeitura": {
        "type": "object",
        "properties": {
          "codigoNfe": {
            "type": "string",
            "description": "Código de bandeira da NF-e (tBand: 01 Visa, 02 Mastercard, 06 Elo, 99 outros).",
            "nullable": true
          },
          "nome": {
            "type": "string",
            "description": "Nome do cadastro de cartão na loja.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CarneLeitura": {
        "type": "object",
        "properties": {
          "numero": {
            "type": "string",
            "description": "Número do carnê.",
            "nullable": true
          },
          "tipo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CodigoDescricaoLeitura"
              }
            ],
            "description": "Tipo de carnê cadastrado na loja (ex.: CREDIARIO LOJA, SALDO A RECEBER)."
          }
        },
        "additionalProperties": false
      },
      "ClienteDocumentoLeitura": {
        "type": "object",
        "properties": {
          "cpf": {
            "type": "string",
            "description": "CPF (sem máscara) quando pessoa física. Omitido quando não há valor.",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ (sem máscara) quando pessoa jurídica. Omitido quando não há valor.",
            "nullable": true
          },
          "nome": {
            "type": "string",
            "description": "Nome do cliente.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ClienteLeitura": {
        "required": [
          "consentimentoLgpd"
        ],
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do cliente.",
            "nullable": true
          },
          "cpf": {
            "type": "string",
            "description": "CPF (11 dígitos, sem máscara) — pessoa física. Omitido quando não há valor.",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ (14 dígitos, sem máscara) — pessoa jurídica. Omitido quando não há valor.",
            "nullable": true
          },
          "dataNascimento": {
            "type": "string",
            "description": "Data de nascimento (YYYY-MM-DD). Omitido quando não há valor.",
            "format": "date",
            "nullable": true
          },
          "idade": {
            "type": "integer",
            "description": "Idade em anos, calculada da data de nascimento. Omitido quando não há valor.",
            "format": "int32",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "E-mail; mascarado (nulo) quando o consentimento LGPD foi recusado.",
            "nullable": true
          },
          "celular": {
            "type": "string",
            "description": "Celular normalizado para WhatsApp (55DDD9XXXXXXXX) ou nulo.",
            "nullable": true
          },
          "telefone1": {
            "type": "string",
            "description": "Telefones adicionais, apenas dígitos, sem normalização de DDI.",
            "nullable": true
          },
          "telefone2": {
            "type": "string",
            "description": "Segundo telefone adicional, apenas dígitos. Omitido quando não há valor.",
            "nullable": true
          },
          "endereco": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EnderecoLeitura"
              }
            ],
            "description": "Endereço de cadastro; mascarado (nulo) quando o consentimento foi recusado."
          },
          "ativo": {
            "type": "boolean",
            "description": "Sempre true no modo snapshot (só ativos). No modo delta (`alteradoEm[gte]`) clientes desativados aparecem com false — sem isso o consumidor nunca saberia da desativação."
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração ou inclusão do cadastro — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água do delta.",
            "format": "date-time",
            "nullable": true
          },
          "consentimentoLgpd": {
            "type": "string",
            "description": "naoEnviado | naoRespondido | aguardando | aceitou | recusou.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ClienteResumoLeitura": {
        "required": [
          "consentimentoLgpd"
        ],
        "type": "object",
        "properties": {
          "cpf": {
            "type": "string",
            "description": "CPF do cliente (sem máscara). Omitido quando não há valor.",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ do cliente (sem máscara). Omitido quando não há valor.",
            "nullable": true
          },
          "nome": {
            "type": "string",
            "description": "Nome do cliente.",
            "nullable": true
          },
          "celular": {
            "type": "string",
            "description": "Celular normalizado para WhatsApp (55DDD9XXXXXXXX); mascarado (nulo) quando o consentimento LGPD foi recusado.",
            "nullable": true
          },
          "email": {
            "type": "string",
            "description": "E-mail; mascarado (nulo) quando o consentimento LGPD foi recusado.",
            "nullable": true
          },
          "consentimentoLgpd": {
            "type": "string",
            "description": "naoEnviado | naoRespondido | aguardando | aceitou | recusou.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "CodigoDescricaoLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código no ERP.",
            "format": "int32"
          },
          "descricao": {
            "type": "string",
            "description": "Descrição.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ConvenioLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código do convênio no ERP (estável na instalação).",
            "format": "int32"
          },
          "nome": {
            "type": "string",
            "description": "Nome do convênio como cadastrado na loja.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ConvenioVendaLeitura": {
        "required": [
          "convenio",
          "id",
          "pagamentos",
          "tipo"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Id estável da parte paga por convênio nesta venda.",
            "format": "int32"
          },
          "convenio": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ConvenioLeitura"
              }
            ],
            "description": "Convênio (ou ticket) que paga esta parte da venda."
          },
          "tipo": {
            "type": "string",
            "description": "convenio | ticket | outro.",
            "nullable": true
          },
          "valor": {
            "type": "number",
            "description": "Valor desta venda pago pelo convênio.",
            "format": "double"
          },
          "numeroDocumento": {
            "type": "string",
            "description": "Documento informado na venda (autorização, guia, matrícula…); ausente se não informado.",
            "nullable": true
          },
          "responsavel": {
            "type": "string",
            "description": "Responsável informado na venda; ausente se não informado.",
            "nullable": true
          },
          "fatura": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FaturaVendaLeitura"
              }
            ],
            "description": "Fatura de COBRANÇA do convênio (pode agrupar várias vendas: `fatura.vendas`); ausente enquanto o convênio não é faturado."
          },
          "pagamentos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PagamentoVendaLeitura"
            },
            "description": "Parcelas da fatura do convênio — a mesma forma e o mesmo `id` de `pagamentos` (`dataPagamento` = quando o convênio pagou). `[]` sem fatura.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DevolucaoLeitura": {
        "required": [
          "codDevolucao",
          "itens",
          "tipo"
        ],
        "type": "object",
        "properties": {
          "codDevolucao": {
            "type": "integer",
            "description": "Identificador da devolução — a chave de `/devolucoes/{codDevolucao}`.",
            "format": "int32"
          },
          "numeroDevolucao": {
            "type": "integer",
            "description": "Número da devolução no ERP (exibição).",
            "format": "int32",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data da devolução (a data usada no recorte por período).",
            "format": "date",
            "nullable": true
          },
          "tipo": {
            "type": "string",
            "description": "mercadoria | brinde | outro.",
            "nullable": true
          },
          "naturezaOperacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NaturezaOperacaoLeitura"
              }
            ],
            "description": "Natureza da nota de devolução (ex.: `1.202` devolução de venda)."
          },
          "total": {
            "type": "number",
            "description": "Valor total devolvido.",
            "format": "double"
          },
          "vendaOrigem": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VendaOrigemLeitura"
              }
            ],
            "description": "Venda de origem; ausente quando a devolução foi lançada sem vínculo."
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteDocumentoLeitura"
              }
            ],
            "description": "Mesmo bloco de /vendas: `null` explícito quando o cliente não é identificado."
          },
          "vendedor": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VendedorLeitura"
              }
            ],
            "description": "Vendedor registrado na devolução. Omitido quando não há valor."
          },
          "creditoGerado": {
            "type": "number",
            "description": "Crédito gerado para o cliente pela devolução; ausente quando não gerou crédito.",
            "format": "double",
            "nullable": true
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendaItemLeitura"
            },
            "description": "Itens devolvidos — numa devolução parcial, só o que voltou.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "DevolucaoRefLeitura": {
        "required": [
          "codDevolucao"
        ],
        "type": "object",
        "properties": {
          "codDevolucao": {
            "type": "integer",
            "description": "Identificador da devolução — detalhe em `/devolucoes/{codDevolucao}`.",
            "format": "int32"
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data da devolução.",
            "format": "date",
            "nullable": true
          },
          "total": {
            "type": "number",
            "description": "Valor total devolvido.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "DioptriaLeitura": {
        "type": "object",
        "properties": {
          "esferico": {
            "type": "number",
            "description": "Grau esférico (dioptrias).",
            "format": "double",
            "nullable": true
          },
          "cilindrico": {
            "type": "number",
            "description": "Grau cilíndrico (dioptrias).",
            "format": "double",
            "nullable": true
          },
          "eixo": {
            "type": "number",
            "description": "Eixo do cilindro (graus).",
            "format": "double",
            "nullable": true
          },
          "co": {
            "type": "number",
            "description": "Coeficiente do olho, como registrado na receita.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "EmpresaLeitura": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome (razão social ou fantasia) da filial.",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ sem máscara — o valor a usar em `empresaCnpj` nos demais endpoints.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "EnderecoLeitura": {
        "type": "object",
        "properties": {
          "cep": {
            "type": "string",
            "description": "CEP (8 dígitos).",
            "nullable": true
          },
          "uf": {
            "type": "string",
            "description": "Sigla da UF.",
            "nullable": true
          },
          "cidade": {
            "type": "string",
            "description": "Município.",
            "nullable": true
          },
          "bairro": {
            "type": "string",
            "description": "Bairro.",
            "nullable": true
          },
          "logradouro": {
            "type": "string",
            "description": "Logradouro (rua, avenida…).",
            "nullable": true
          },
          "numero": {
            "type": "string",
            "description": "Número.",
            "nullable": true
          },
          "complemento": {
            "type": "string",
            "description": "Complemento.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "EstoqueEcommerce": {
        "required": [
          "codItem",
          "id"
        ],
        "type": "object",
        "properties": {
          "codEstoqueLocal": {
            "type": "integer",
            "description": "Local de estoque: sempre 1 (prateleira, o saldo disponível para venda) desde a v1.8.",
            "format": "int32"
          },
          "codItem": {
            "type": "string",
            "description": "Código do item no ERP.",
            "nullable": true
          },
          "id": {
            "type": "string",
            "description": "Código externo (SKU) do produto — o `id` de `/ecommerce/produtos`.",
            "nullable": true
          },
          "saldo": {
            "type": "number",
            "description": "Saldo na prateleira. Pode ser negativo (vendido além do estoque): trate como zero.",
            "format": "double"
          },
          "minimo": {
            "type": "number",
            "description": "Estoque mínimo configurado. Omitido quando não há valor.",
            "format": "double",
            "nullable": true
          },
          "maximo": {
            "type": "number",
            "description": "Estoque máximo configurado. Omitido quando não há valor.",
            "format": "double",
            "nullable": true
          },
          "dataUltimoMovimento": {
            "type": "string",
            "description": "Data e hora do último movimento de estoque. Omitido quando não há valor.",
            "format": "date-time",
            "nullable": true
          },
          "ultimaAlteracao": {
            "type": "string",
            "description": "Data e hora da última alteração do saldo (o mesmo valor de `alteradoEm`; mantido por compatibilidade).",
            "format": "date-time"
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração do saldo — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água.",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "EtapaAtualLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código da etapa no ERP (etapas são parametrizadas por instalação).",
            "format": "int32"
          },
          "nome": {
            "type": "string",
            "description": "Nome da etapa, quando é uma etapa padrão do ERP; nulo para etapas parametrizadas na instalação.",
            "nullable": true
          },
          "desde": {
            "type": "string",
            "description": "Data e hora em que a O.S. entrou na etapa atual.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "EtapaHistoricoLeitura": {
        "required": [
          "etapa"
        ],
        "type": "object",
        "properties": {
          "etapa": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EtapaLeitura"
              }
            ],
            "description": "A etapa."
          },
          "entrada": {
            "type": "string",
            "description": "Data e hora de entrada na etapa.",
            "format": "date-time",
            "nullable": true
          },
          "saida": {
            "type": "string",
            "description": "Data e hora de saída da etapa; ausente na etapa atual.",
            "format": "date-time",
            "nullable": true
          },
          "motivo": {
            "type": "string",
            "description": "Motivo registrado na troca de etapa. Omitido quando não há valor.",
            "nullable": true
          },
          "observacao": {
            "type": "string",
            "description": "Observação registrada na troca de etapa. Omitido quando não há valor.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "EtapaLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código da etapa no ERP (etapas são parametrizadas por instalação).",
            "format": "int32"
          },
          "nome": {
            "type": "string",
            "description": "Nome da etapa, quando é uma etapa padrão do ERP; nulo para etapas parametrizadas na instalação.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FaturaVendaLeitura": {
        "required": [
          "vendas"
        ],
        "type": "object",
        "properties": {
          "numero": {
            "type": "integer",
            "description": "Número natural da fatura; ausente quando a fatura não é numerada.",
            "format": "int32",
            "nullable": true
          },
          "valorTotal": {
            "type": "number",
            "description": "Valor total da fatura inteira (todas as vendas que ela cobre).",
            "format": "double"
          },
          "vendas": {
            "type": "array",
            "items": {
              "type": "integer",
              "format": "int32"
            },
            "description": "Vendas (codVenda) cobertas pela fatura, na empresa consultada.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "FinanceiroClienteLeitura": {
        "type": "object",
        "properties": {
          "cpf": {
            "type": "string",
            "description": "CPF (sem máscara) quando pessoa física. Omitido quando não há valor.",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ (sem máscara) quando pessoa jurídica. Omitido quando não há valor.",
            "nullable": true
          },
          "nome": {
            "type": "string",
            "description": "Nome do cliente.",
            "nullable": true
          },
          "ativo": {
            "type": "boolean",
            "description": "Cadastro ativo no ERP."
          }
        },
        "additionalProperties": false
      },
      "FormaPagamentoLeitura": {
        "required": [
          "tipo"
        ],
        "type": "object",
        "properties": {
          "tipo": {
            "type": "string",
            "description": "dinheiro | cheque | cartaoCredito | cartaoDebito | pix | boleto | banco | carne | creditoCliente | outro.",
            "nullable": true
          },
          "bandeira": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BandeiraLeitura"
              }
            ],
            "description": "Bandeira do cartão (cartão e PIX de maquininha)."
          },
          "numeroParcela": {
            "type": "integer",
            "description": "Cartão: número desta parcela (1, 2, 3…) e o total de parcelas da compra no cartão.",
            "format": "int32",
            "nullable": true
          },
          "totalParcelas": {
            "type": "integer",
            "description": "Cartão: total de parcelas da compra no cartão (a maior parcela da mesma compra).",
            "format": "int32",
            "nullable": true
          },
          "nsu": {
            "type": "string",
            "description": "Cartão: NSU da transação.",
            "nullable": true
          },
          "codigoAutorizacao": {
            "type": "string",
            "description": "Cartão: código de autorização da transação.",
            "nullable": true
          },
          "carne": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CarneLeitura"
              }
            ],
            "description": "Carnê: número e tipo do carnê (ex.: SALDO A RECEBER)."
          }
        },
        "additionalProperties": false
      },
      "ImagemLinkLeitura": {
        "required": [
          "url"
        ],
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "URL relativa à raiz do host (mesma autenticação Bearer da API).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "LancamentoLeitura": {
        "required": [
          "dataVencimento",
          "id",
          "situacao",
          "valorTotal"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identificador estável da parcela — usado no boleto e igual ao `id` das parcelas em `/vendas` (`incluir=pagamentos`).",
            "format": "int32"
          },
          "numeroFatura": {
            "type": "string",
            "description": "Número da fatura (agrupamento), quando houver — exibição; a área de faturas não é exposta. Omitido quando o lançamento não tem fatura numerada.",
            "nullable": true
          },
          "numeroDocumento": {
            "type": "string",
            "description": "Documento da parcela no ERP (ex.: `84213/1`).",
            "nullable": true
          },
          "dataVencimento": {
            "type": "string",
            "description": "Vencimento da parcela.",
            "format": "date"
          },
          "dataPagamento": {
            "type": "string",
            "description": "Data do pagamento — ou do recebimento, quando a parcela foi recebida (cheque/cartão) e ainda não liquidada: para o cliente ela está paga. Omitido quando em aberto.",
            "format": "date",
            "nullable": true
          },
          "valorTotal": {
            "type": "number",
            "description": "Valor da parcela.",
            "format": "double"
          },
          "situacao": {
            "type": "string",
            "description": "pago | pagoEmAtraso | emAberto | vencido — calculado no servidor, com tolerância de fim de semana no vencimento.",
            "nullable": true
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteDocumentoLeitura"
              }
            ],
            "description": "Cliente devedor: `{ cpf?, cnpj?, nome? }` quando identificado; `null` (emitido) quando não — só ocorre na cobrança (a visão por documento é sempre identificada)."
          },
          "empresaCnpj": {
            "type": "string",
            "description": "CNPJ da empresa credora — presente apenas na visão de cobrança (várias empresas).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "MedicoLeitura": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do médico.",
            "nullable": true
          },
          "registroProfissional": {
            "type": "string",
            "description": "Registro profissional como texto livre (CRM/CBOO).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "NaturezaOperacaoLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "Código da natureza como cadastrado na loja (ex.: `5.102`, `5.922`, `5.910-1`, `5910-1`); os 4 primeiros dígitos são o CFOP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição da natureza como cadastrada na loja.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "NotaFiscalLeitura": {
        "required": [
          "dataEmissao",
          "id",
          "tipo",
          "valorTotal"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identificador OPACO da nota para download (XML/PDF) — estável no tenant; não interpretar.",
            "format": "int32"
          },
          "tipo": {
            "type": "string",
            "description": "nfe | nfce | nfse. NFC-e é a NF-e modelo 65 (venda ao consumidor, cliente pode não ser identificado); os tipos aposentados do ERP (papel, SAT, RPS) nunca aparecem.",
            "nullable": true
          },
          "numero": {
            "type": "integer",
            "description": "Número da nota (dado; não é único isoladamente — o download usa `id`).",
            "format": "int64",
            "nullable": true
          },
          "serie": {
            "type": "string",
            "description": "Série da nota.",
            "nullable": true
          },
          "chave": {
            "type": "string",
            "description": "Chave de acesso de 44 dígitos — NF-e e NFC-e (nula na NFS-e, que não tem chave escalar).",
            "nullable": true
          },
          "numeroFatura": {
            "type": "string",
            "description": "Número da fatura (agrupamento) quando a nota vem de uma transação faturada com número — omitido caso contrário.",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data de emissão da nota.",
            "format": "date"
          },
          "valorTotal": {
            "type": "number",
            "description": "Valor total da nota.",
            "format": "double"
          },
          "temXml": {
            "type": "boolean",
            "description": "Existe XML armazenado (NF-e ou NFS-e)."
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteDocumentoLeitura"
              }
            ],
            "description": "Cliente dono da nota (`{ cpf?, cnpj?, nome? }`) — sempre identificado nesta visão (a nota é escopada pelo cpf/cnpj informado)."
          }
        },
        "additionalProperties": false
      },
      "NotaFiscalVendaLeitura": {
        "type": "object",
        "properties": {
          "numero": {
            "type": "integer",
            "description": "Número da nota fiscal.",
            "format": "int32",
            "nullable": true
          },
          "serie": {
            "type": "string",
            "description": "Série da nota fiscal.",
            "nullable": true
          },
          "modelo": {
            "type": "string",
            "description": "nfe | nfce | nfse | papel | sat | rps.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "autorizada | pendente | enviada | rejeitada | denegada | cancelada | inutilizada | emitida (papel).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemCompraLeitura": {
        "required": [
          "numero"
        ],
        "type": "object",
        "properties": {
          "numero": {
            "type": "integer",
            "description": "Número da ordem de compra (pedido ao laboratório/fornecedor).",
            "format": "int32"
          },
          "situacao": {
            "type": "string",
            "description": "aberta | aprovada | atendida; nulo para código desconhecido.",
            "nullable": true
          },
          "notaFiscal": {
            "type": "string",
            "description": "Numeração da NF de compra quando existente; nulo caso contrário.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoItemLeitura": {
        "required": [
          "tipoItem"
        ],
        "type": "object",
        "properties": {
          "codItem": {
            "type": "string",
            "description": "Código do item no ERP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do item.",
            "nullable": true
          },
          "tipoItem": {
            "type": "string",
            "description": "produto | lente | armacao | servico | outros.",
            "nullable": true
          },
          "quantidade": {
            "type": "number",
            "description": "Quantidade.",
            "format": "double"
          },
          "valorUnitario": {
            "type": "number",
            "description": "Valor unitário.",
            "format": "double"
          },
          "total": {
            "type": "number",
            "description": "Valor total do item.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLab": {
        "type": "object",
        "properties": {
          "numero": {
            "type": "integer",
            "description": "Número da O.S. no laboratório. Só na resposta (ignorado no envio).",
            "format": "int64",
            "nullable": true
          },
          "idPedidoOtica": {
            "type": "string",
            "description": "Identificador do pedido na ótica (1 a 30 caracteres), obrigatório. Chave de idempotência por ótica: reenviar o mesmo valor devolve a O.S. já gravada.",
            "nullable": true
          },
          "oticaCnpj": {
            "type": "string",
            "description": "CNPJ da ótica (cliente do laboratório) que fez o pedido, com ou sem máscara, obrigatório. Deve ser um cliente ativo do laboratório.",
            "nullable": true
          },
          "observacao": {
            "type": "string",
            "description": "Observação livre da O.S.",
            "nullable": true
          },
          "receita": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabReceita"
              }
            ],
            "description": "Receita: ao menos um olho."
          },
          "armacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabArmacao"
              }
            ],
            "description": "Medidas e dados da armação."
          },
          "parametros": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabParametros"
              }
            ],
            "description": "Parâmetros de montagem, por olho, e o olho dominante."
          },
          "paciente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabPaciente"
              }
            ],
            "description": "Paciente (usuário dos óculos)."
          },
          "medico": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabMedico"
              }
            ],
            "description": "Profissional que assinou a receita."
          },
          "vendedor": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabVendedor"
              }
            ],
            "description": "Vendedor da ótica."
          },
          "servicos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabServico"
            },
            "description": "Serviços (tratamentos, coloração, montagem…), pelos códigos de GET /dilab/servicos.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação da O.S.: aberta, aprovada, encerrada, cancelada ou recusada (pelo laboratório). Só na resposta.",
            "nullable": true
          },
          "recusa": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabRecusa"
              }
            ],
            "description": "A recusa do laboratório (data e motivo), quando situacao é recusada. Só na resposta."
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabArmacao": {
        "type": "object",
        "properties": {
          "vertical": {
            "type": "number",
            "description": "Altura do aro, AA (mm).",
            "format": "double",
            "nullable": true
          },
          "horizontal": {
            "type": "number",
            "description": "Largura do aro, H (mm).",
            "format": "double",
            "nullable": true
          },
          "ponte": {
            "type": "number",
            "description": "Ponte (mm).",
            "format": "double",
            "nullable": true
          },
          "diametroMaior": {
            "type": "number",
            "description": "Diagonal maior, MD (mm).",
            "format": "double",
            "nullable": true
          },
          "material": {
            "type": "integer",
            "description": "Código do material da armação no laboratório.",
            "format": "int32",
            "nullable": true
          },
          "formatoAro": {
            "type": "integer",
            "description": "Código do formato do aro no laboratório.",
            "format": "int32",
            "nullable": true
          },
          "marca": {
            "type": "string",
            "description": "Marca da armação.",
            "nullable": true
          },
          "referencia": {
            "type": "string",
            "description": "Referência (modelo) da armação.",
            "nullable": true
          },
          "usada": {
            "type": "boolean",
            "description": "A armação é usada (do cliente).",
            "nullable": true
          },
          "leitura": {
            "type": "string",
            "description": "Leitura do traçador (arquivo OMA, texto). Com ela, as medidas vêm da leitura e as faixas da armação não são conferidas.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabEtapa": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código da etapa: 0 inicial, 1 em produção, 2 final da produção, 3 na expedição, 4 expedida.",
            "format": "int32"
          },
          "descricao": {
            "type": "string",
            "description": "Descrição da etapa.",
            "nullable": true
          },
          "data": {
            "type": "string",
            "description": "Data e hora em que a etapa foi alcançada.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabFormatoAro": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código a enviar em armacao.formatoAro.",
            "format": "int32"
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do formato no laboratório.",
            "nullable": true
          },
          "imagem": {
            "type": "string",
            "description": "Imagem do formato (PNG) em base64.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabMaterial": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código a enviar em armacao.material.",
            "format": "int32"
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do material no laboratório.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabMedico": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do profissional.",
            "nullable": true
          },
          "crm": {
            "type": "string",
            "description": "Registro profissional (CRM ou equivalente).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabPaciente": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do paciente.",
            "nullable": true
          },
          "cpf": {
            "type": "string",
            "description": "CPF do paciente.",
            "nullable": true
          },
          "iniciaisPaciente": {
            "type": "string",
            "description": "Iniciais para gravar na lente. Sem elas, o laboratório pode extraí-las do nome (conforme a configuração).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabParametros": {
        "type": "object",
        "properties": {
          "olhoDominante": {
            "type": "string",
            "description": "Olho dominante: DIREITO, ESQUERDO ou AMBOS.",
            "nullable": true
          },
          "olhoDireito": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabParametrosOlho"
              }
            ],
            "description": "Parâmetros do olho direito."
          },
          "olhoEsquerdo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabParametrosOlho"
              }
            ],
            "description": "Parâmetros do olho esquerdo."
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabParametrosOlho": {
        "type": "object",
        "properties": {
          "dnpPerto": {
            "type": "number",
            "description": "DNP de perto (mm).",
            "format": "double",
            "nullable": true
          },
          "distanciaVertice": {
            "type": "number",
            "description": "Distância vértice (mm).",
            "format": "double",
            "nullable": true
          },
          "cro": {
            "type": "number",
            "description": "Centro de rotação ocular, CRO (mm).",
            "format": "double",
            "nullable": true
          },
          "anguloPantoscopico": {
            "type": "number",
            "description": "Ângulo pantoscópico (graus).",
            "format": "double",
            "nullable": true
          },
          "anguloCurvatura": {
            "type": "number",
            "description": "Ângulo de curvatura da armação (graus).",
            "format": "double",
            "nullable": true
          },
          "distanciaLeitura": {
            "type": "number",
            "description": "Distância de leitura (cm).",
            "format": "double",
            "nullable": true
          },
          "coeficienteHE": {
            "type": "number",
            "description": "Coeficiente HE (movimento de cabeça e olhos).",
            "format": "double",
            "nullable": true
          },
          "coeficienteST": {
            "type": "number",
            "description": "Coeficiente ST (estabilidade).",
            "format": "double",
            "nullable": true
          },
          "distanciaProgressao": {
            "type": "number",
            "description": "Distância de progressão (mm).",
            "format": "double",
            "nullable": true
          },
          "cvp": {
            "type": "string",
            "description": "CVP.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabReceita": {
        "type": "object",
        "properties": {
          "olhoDireito": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabReceitaOlho"
              }
            ],
            "description": "Olho direito (OD)."
          },
          "olhoEsquerdo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabReceitaOlho"
              }
            ],
            "description": "Olho esquerdo (OE)."
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabReceitaOlho": {
        "type": "object",
        "properties": {
          "descricaoLente": {
            "type": "string",
            "description": "Descrição da lente desejada (até 250 caracteres), obrigatória. O laboratório grava a O.S. com uma lente genérica e a troca pela lente real; depois da troca, as consultas trazem aqui a descrição da lente real.",
            "nullable": true
          },
          "grauEsferico": {
            "type": "number",
            "description": "Grau esférico (dioptrias).",
            "format": "double",
            "nullable": true
          },
          "grauCilindro": {
            "type": "number",
            "description": "Grau cilíndrico (dioptrias). Zero equivale a sem cilindro (o eixo é ignorado).",
            "format": "double",
            "nullable": true
          },
          "eixo": {
            "type": "number",
            "description": "Eixo do cilindro, de 0 a 180 graus.",
            "format": "double",
            "nullable": true
          },
          "dnp": {
            "type": "number",
            "description": "DNP de longe (mm).",
            "format": "double",
            "nullable": true
          },
          "adicao": {
            "type": "number",
            "description": "Adição (dioptrias).",
            "format": "double",
            "nullable": true
          },
          "altura": {
            "type": "number",
            "description": "Altura de montagem (mm).",
            "format": "double",
            "nullable": true
          },
          "base": {
            "type": "number",
            "description": "Base da lente.",
            "format": "double",
            "nullable": true
          },
          "eixoPrismaHorizontal": {
            "type": "string",
            "description": "Base do prisma horizontal: NASAL ou TEMPORAL, ou o ângulo em graus (0 a 360).",
            "nullable": true
          },
          "valorPrismaHorizontal": {
            "type": "number",
            "description": "Valor do prisma horizontal (dioptrias prismáticas).",
            "format": "double",
            "nullable": true
          },
          "eixoPrismaVertical": {
            "type": "string",
            "description": "Base do prisma vertical: SUPERIOR ou INFERIOR, ou o ângulo em graus (0 a 360).",
            "nullable": true
          },
          "valorPrismaVertical": {
            "type": "number",
            "description": "Valor do prisma vertical (dioptrias prismáticas).",
            "format": "double",
            "nullable": true
          },
          "ct": {
            "type": "number",
            "description": "Espessura no centro (mm).",
            "format": "double",
            "nullable": true
          },
          "et": {
            "type": "number",
            "description": "Espessura na borda (mm).",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabRecusa": {
        "type": "object",
        "properties": {
          "data": {
            "type": "string",
            "description": "Data e hora da recusa.",
            "format": "date-time",
            "nullable": true
          },
          "motivo": {
            "type": "string",
            "description": "Motivo informado pelo laboratório.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabResumo": {
        "type": "object",
        "properties": {
          "numero": {
            "type": "integer",
            "description": "Número da O.S. no laboratório.",
            "format": "int64"
          },
          "idPedidoOtica": {
            "type": "string",
            "description": "Identificador do pedido na ótica.",
            "nullable": true
          },
          "oticaCnpj": {
            "type": "string",
            "description": "CNPJ da ótica.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Situação: aberta, aprovada, encerrada, cancelada ou recusada.",
            "nullable": true
          },
          "dataInclusao": {
            "type": "string",
            "description": "Data e hora em que a O.S. foi recebida.",
            "format": "date-time"
          },
          "dataRecusa": {
            "type": "string",
            "description": "Data e hora da recusa, quando recusada.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabServico": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "Código do serviço, como em GET /dilab/servicos, obrigatório.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do serviço no laboratório. Só na resposta (ignorada no envio).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabServicoDisponivel": {
        "type": "object",
        "properties": {
          "codigo": {
            "type": "string",
            "description": "Código a enviar em servicos[].codigo.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do serviço no laboratório.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabStatus": {
        "type": "object",
        "properties": {
          "situacao": {
            "type": "string",
            "description": "Situação: aberta, aprovada, encerrada, cancelada ou recusada.",
            "nullable": true
          },
          "recusa": {
            "allOf": [
              {
                "$ref": "#/components/schemas/OrdemServicoLabRecusa"
              }
            ],
            "description": "A recusa do laboratório (data e motivo); só quando situacao é recusada."
          },
          "etapas": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabEtapa"
            },
            "description": "Etapas da produção já alcançadas, em ordem. Vazia na O.S. recusada.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLabVendedor": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do vendedor.",
            "nullable": true
          },
          "cpf": {
            "type": "string",
            "description": "CPF do vendedor.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "OrdemServicoLeitura": {
        "required": [
          "cliente",
          "etapaAtual",
          "numeroOrdemServico",
          "situacao"
        ],
        "type": "object",
        "properties": {
          "numeroOrdemServico": {
            "type": "integer",
            "description": "Número da O.S. — a chave usada em `/ordens-servico/{numero}`.",
            "format": "int32"
          },
          "situacao": {
            "type": "string",
            "description": "orcamento | aberta | pronta | entregue.",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data de emissão da O.S.",
            "format": "date",
            "nullable": true
          },
          "dataPrevisao": {
            "type": "string",
            "description": "Previsão de entrega ao cliente (data e hora).",
            "format": "date-time",
            "nullable": true
          },
          "dataServicoPronto": {
            "type": "string",
            "description": "Data em que o serviço ficou pronto; ausente enquanto não fica.",
            "format": "date",
            "nullable": true
          },
          "dataEntrega": {
            "type": "string",
            "description": "Data da entrega ao cliente; ausente enquanto não entregue.",
            "format": "date",
            "nullable": true
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração da O.S. (toda troca de etapa conta) — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água do polling.",
            "format": "date-time",
            "nullable": true
          },
          "garantia": {
            "type": "boolean",
            "description": "A O.S. é de garantia (refação/troca)."
          },
          "paciente": {
            "type": "string",
            "description": "Nome do paciente da receita, quando difere do cliente; omitido sem receita.",
            "nullable": true
          },
          "temReceita": {
            "type": "boolean",
            "description": "Sinaliza que /ordens-servico/{numero}/receita tem conteúdo — evita sondagem."
          },
          "etapaAtual": {
            "allOf": [
              {
                "$ref": "#/components/schemas/EtapaAtualLeitura"
              }
            ],
            "description": "Etapa de produção atual, com a data de entrada nela."
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteResumoLeitura"
              }
            ],
            "description": "Cliente da O.S. (contatos mascarados quando o consentimento LGPD foi recusado)."
          },
          "vendedor": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VendedorLeitura"
              }
            ],
            "description": "Vendedor da O.S. (o principal) — o mesmo objeto `vendedor` de /vendas."
          },
          "historico": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EtapaHistoricoLeitura"
            },
            "description": "Histórico de etapas — somente na consulta individual.",
            "nullable": true
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoItemLeitura"
            },
            "description": "Itens (produtos e serviços) da OS. Sempre presentes na consulta individual; na listagem só com `incluir=itens` (nulo = não solicitado, omitido do JSON).",
            "nullable": true
          },
          "ordensCompra": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemCompraLeitura"
            },
            "description": "Ordens de compra vinculadas à OS. Sempre presentes na consulta individual; na listagem só com `incluir=ordensCompra` (nulo = não solicitado).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PacienteLeitura": {
        "type": "object",
        "properties": {
          "nome": {
            "type": "string",
            "description": "Nome do paciente.",
            "nullable": true
          },
          "cpf": {
            "type": "string",
            "description": "CPF do paciente (sem máscara). Omitido quando não há valor.",
            "nullable": true
          },
          "dataNascimento": {
            "type": "string",
            "description": "Data de nascimento do paciente. Omitido quando não há valor.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PagamentoVendaLeitura": {
        "required": [
          "forma",
          "id",
          "situacao"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Id estável da parcela — o mesmo `id` de /financeiro/lancamentos.",
            "format": "int32"
          },
          "numeroDocumento": {
            "type": "string",
            "description": "Documento da parcela no ERP (ex.: `7227/1`; `…/U` = parcela única).",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "emAberto | vencido | pago | pagoEmAtraso (mesma regra da área financeiro).",
            "nullable": true
          },
          "valor": {
            "type": "number",
            "description": "Valor atual da parcela.",
            "format": "double"
          },
          "valorOriginal": {
            "type": "number",
            "description": "Valor quando a parcela foi criada.",
            "format": "double"
          },
          "valorPago": {
            "type": "number",
            "description": "Valor pago (`0` enquanto em aberto).",
            "format": "double"
          },
          "juros": {
            "type": "number",
            "description": "Juros cobrados no pagamento.",
            "format": "double"
          },
          "desconto": {
            "type": "number",
            "description": "Desconto concedido no pagamento.",
            "format": "double"
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data de emissão da parcela. Em cartão, PIX, dinheiro e crédito do cliente é quando o CLIENTE pagou.",
            "format": "date",
            "nullable": true
          },
          "dataVencimento": {
            "type": "string",
            "description": "Vencimento atual. Em cartão/PIX de maquininha é a previsão do repasse da adquirente.",
            "format": "date",
            "nullable": true
          },
          "dataVencimentoOriginal": {
            "type": "string",
            "description": "Vencimento quando a parcela foi criada — difere de `dataVencimento` quando foi prorrogado.",
            "format": "date",
            "nullable": true
          },
          "dataPagamento": {
            "type": "string",
            "description": "Data de pagamento (ou de recebimento, para cheque/cartão a liquidar); ausente se em aberto.",
            "format": "date",
            "nullable": true
          },
          "forma": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FormaPagamentoLeitura"
              }
            ],
            "description": "Forma de pagamento da parcela."
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraClienteLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClienteLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraDevolucaoLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DevolucaoLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraEmpresaLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EmpresaLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraEstoqueEcommerce": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EstoqueEcommerce"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraFinanceiroClienteLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FinanceiroClienteLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraLancamentoLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LancamentoLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraNotaFiscalLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NotaFiscalLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraOrdemServicoLabFormatoAro": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabFormatoAro"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraOrdemServicoLabMaterial": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabMaterial"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraOrdemServicoLabResumo": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabResumo"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraOrdemServicoLabServicoDisponivel": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLabServicoDisponivel"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraOrdemServicoLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrdemServicoLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraPedidoEcommerceResumo": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PedidoEcommerceResumo"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraProdutoEcommerce": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProdutoEcommerce"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PaginaLeituraVendaLeitura": {
        "required": [
          "data"
        ],
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendaLeitura"
            },
            "description": "Itens desta página.",
            "nullable": true
          },
          "nextCursor": {
            "type": "string",
            "description": "Cursor da próxima página — repita a chamada com `cursor` igual a este valor e os MESMOS filtros. Ausente = fim da lista (nunca compare o tamanho de `data` com o `limite`).",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerce": {
        "required": [
          "cliente",
          "numeroPedido"
        ],
        "type": "object",
        "properties": {
          "numeroPedido": {
            "maxLength": 30,
            "type": "string",
            "description": "Identificador do pedido na plataforma de e-commerce de origem. Chave de idempotência: o mesmo número reenviado pelo mesmo integrador devolve o pedido já gravado. Vai para a NF-e (\"Pedido externo\") — daí o limite de 30 caracteres.",
            "nullable": true
          },
          "canal": {
            "maxLength": 30,
            "type": "string",
            "description": "Canal de venda — texto livre do integrador (ex.: ecommerce, marketplace). Padrão: ecommerce.",
            "nullable": true
          },
          "observacao": {
            "maxLength": 250,
            "type": "string",
            "description": "Observação livre do pedido.",
            "nullable": true
          },
          "dataHoraPrevisao": {
            "type": "string",
            "description": "Previsão de entrega ao cliente (data e hora, fuso da instalação). Opcional.",
            "format": "date-time",
            "nullable": true
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceCliente"
              }
            ],
            "description": "Consumidor do pedido (cadastrado ou atualizado na loja pelo CPF/CNPJ)."
          },
          "entregaEndereco": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceEndereco"
              }
            ],
            "description": "Endereço de entrega — obrigatório quando há frete."
          },
          "tipoExpedicao": {
            "maxLength": 30,
            "type": "string",
            "description": "Descrição livre da modalidade de envio (ex.: Sedex).",
            "nullable": true
          },
          "vendedor": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceVendedor"
              }
            ],
            "description": "Vendedor do pedido. Sem ele (ou sem CPF cadastrado na loja), o vendedor é \"VENDEDOR ECOMMERCE\"."
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PedidoEcommerceItem"
            },
            "description": "Itens do pedido.",
            "nullable": true
          },
          "pagamentos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PedidoEcommercePagamento"
            },
            "description": "Pagamentos do pedido — a soma deve bater com o total (itens − descontos + frete).",
            "nullable": true
          },
          "totalItens": {
            "type": "number",
            "description": "Soma dos itens (quantidade × valor unitário).",
            "format": "double"
          },
          "totalDescontos": {
            "type": "number",
            "description": "Soma dos descontos.",
            "format": "double"
          },
          "totalFrete": {
            "type": "number",
            "description": "Valor do frete cobrado do consumidor.",
            "format": "double"
          },
          "totalPedido": {
            "type": "number",
            "description": "Total do pedido = itens − descontos + frete.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceCancelado": {
        "required": [
          "numeroPedido",
          "situacao"
        ],
        "type": "object",
        "properties": {
          "numeroPedido": {
            "type": "string",
            "description": "Número do pedido cancelado.",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "Sempre `cancelado`.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceCliente": {
        "required": [
          "id"
        ],
        "type": "object",
        "properties": {
          "id": {
            "maxLength": 18,
            "type": "string",
            "description": "CPF ou CNPJ do consumidor, com ou sem máscara.",
            "nullable": true
          },
          "nome": {
            "maxLength": 250,
            "type": "string",
            "description": "Nome do consumidor.",
            "nullable": true
          },
          "dataNascimento": {
            "type": "string",
            "description": "YYYY-MM-DD.",
            "format": "date",
            "nullable": true
          },
          "email": {
            "maxLength": 100,
            "type": "string",
            "description": "E-mail do consumidor.",
            "nullable": true
          },
          "celular": {
            "maxLength": 30,
            "type": "string",
            "description": "Celular do consumidor.",
            "nullable": true
          },
          "telefone": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceTelefone"
              }
            ],
            "description": "Telefones adicionais do consumidor."
          },
          "endereco": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceEndereco"
              }
            ],
            "description": "Endereço de cadastro do consumidor."
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceDetalhe": {
        "required": [
          "numeroPedido",
          "situacao"
        ],
        "type": "object",
        "properties": {
          "numeroPedido": {
            "type": "string",
            "description": "Número do pedido na plataforma (o `numeroPedido` enviado no POST).",
            "nullable": true
          },
          "canal": {
            "type": "string",
            "description": "Canal de venda do pedido, como o integrador enviou (ex.: `ecommerce`, `marketplace`).",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "recebido | aceito | emitidaNf | despachado | entregue | cancelado (pelo integrador) | rejeitado (pela loja).",
            "nullable": true
          },
          "recebidoEm": {
            "type": "string",
            "description": "Quando o pedido foi recebido pela loja.",
            "format": "date-time"
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração do pedido (aceite, NF-e, despacho e entrega contam; pedido cancelado ou rejeitado fica com o momento em que foi recebido) — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água do polling.",
            "format": "date-time",
            "nullable": true
          },
          "total": {
            "type": "number",
            "description": "Total do pedido gravado.",
            "format": "double",
            "nullable": true
          },
          "venda": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceVenda"
              }
            ],
            "description": "Venda gerada pela loja ao aceitar o pedido; ausente antes do aceite."
          },
          "notaFiscal": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceNotaFiscal"
              }
            ],
            "description": "Nota fiscal da venda; ausente antes da emissão."
          },
          "expedicao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceExpedicao"
              }
            ],
            "description": "Dados de despacho (rastreio). Omitido quando não há valor."
          },
          "entregueEm": {
            "type": "string",
            "description": "Data da entrega ao cliente (situação entregue).",
            "format": "date",
            "nullable": true
          },
          "observacao": {
            "type": "string",
            "description": "Observação do pedido.",
            "nullable": true
          },
          "dataHoraPrevisao": {
            "type": "string",
            "description": "Previsão de entrega ao cliente.",
            "format": "date-time",
            "nullable": true
          },
          "totalFrete": {
            "type": "number",
            "description": "Valor do frete.",
            "format": "double",
            "nullable": true
          },
          "tipoExpedicao": {
            "type": "string",
            "description": "Modalidade de envio informada no pedido.",
            "nullable": true
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PedidoEcommerceItemGravado"
            },
            "description": "Itens gravados na loja.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceEndereco": {
        "type": "object",
        "properties": {
          "cep": {
            "maxLength": 10,
            "type": "string",
            "description": "CEP.",
            "nullable": true
          },
          "uf": {
            "maxLength": 2,
            "type": "string",
            "description": "Sigla da UF.",
            "nullable": true
          },
          "cidade": {
            "maxLength": 250,
            "type": "string",
            "description": "Município.",
            "nullable": true
          },
          "bairro": {
            "maxLength": 250,
            "type": "string",
            "description": "Bairro.",
            "nullable": true
          },
          "logradouro": {
            "maxLength": 250,
            "type": "string",
            "description": "Logradouro (rua, avenida…).",
            "nullable": true
          },
          "numero": {
            "maxLength": 30,
            "type": "string",
            "description": "Número.",
            "nullable": true
          },
          "complemento": {
            "maxLength": 50,
            "type": "string",
            "description": "Complemento.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceExpedicao": {
        "type": "object",
        "properties": {
          "codigoRastreio": {
            "type": "string",
            "description": "Código de rastreio da remessa.",
            "nullable": true
          },
          "transportadora": {
            "type": "string",
            "description": "Transportadora.",
            "nullable": true
          },
          "despachadoEm": {
            "type": "string",
            "description": "Data e hora do despacho.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceItem": {
        "required": [
          "id",
          "tipo"
        ],
        "type": "object",
        "properties": {
          "tipo": {
            "maxLength": 20,
            "type": "string",
            "description": "Tipo do item: `PRODUTO`.",
            "nullable": true
          },
          "id": {
            "maxLength": 60,
            "type": "string",
            "description": "Código externo (SKU) do produto — o id de GET /ecommerce/produtos.",
            "nullable": true
          },
          "valorUnitario": {
            "type": "number",
            "description": "Valor unitário (antes do desconto).",
            "format": "double"
          },
          "quantidade": {
            "type": "number",
            "description": "Quantidade.",
            "format": "double"
          },
          "unidade": {
            "maxLength": 6,
            "type": "string",
            "description": "Unidade de venda (ex.: `UN`).",
            "nullable": true
          },
          "descontoUnitario": {
            "type": "number",
            "description": "Desconto por unidade.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceItemGravado": {
        "required": [
          "codItem"
        ],
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Código externo (SKU) do produto.",
            "nullable": true
          },
          "codItem": {
            "type": "string",
            "description": "Código do item no ERP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do item.",
            "nullable": true
          },
          "quantidade": {
            "type": "number",
            "description": "Quantidade.",
            "format": "double"
          },
          "valorUnitario": {
            "type": "number",
            "description": "Valor unitário.",
            "format": "double"
          },
          "descontoUnitario": {
            "type": "number",
            "description": "Desconto por unidade.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceNotaFiscal": {
        "type": "object",
        "properties": {
          "chaveAcesso": {
            "type": "string",
            "description": "Chave de acesso da NF-e (44 dígitos).",
            "nullable": true
          },
          "numero": {
            "type": "integer",
            "description": "Número da nota.",
            "format": "int64",
            "nullable": true
          },
          "serie": {
            "type": "string",
            "description": "Série da nota.",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data e hora de emissão da nota.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommercePagamento": {
        "required": [
          "codigo",
          "valor"
        ],
        "type": "object",
        "properties": {
          "id": {
            "maxLength": 60,
            "type": "string",
            "description": "Identificador da transação na plataforma (opcional).",
            "nullable": true
          },
          "codigo": {
            "maxLength": 20,
            "type": "string",
            "description": "Forma de pagamento: DINHEIRO, CHEQUE, CARTAO_CREDITO, CARTAO_DEBITO, CREDITO (crediário), BOLETO, DEP_BANCARIO, PIX ou SALDO_RECEBER (pagamento na retirada).",
            "nullable": true
          },
          "descricao": {
            "maxLength": 60,
            "type": "string",
            "description": "Descrição livre do pagamento (ex.: a bandeira).",
            "nullable": true
          },
          "valor": {
            "type": "number",
            "description": "Valor pago nesta forma.",
            "format": "double"
          },
          "vencimento": {
            "type": "string",
            "description": "YYYY-MM-DD. Obrigatório para CREDITO (crediário) e SALDO_RECEBER.",
            "format": "date",
            "nullable": true
          },
          "parcelas": {
            "type": "integer",
            "description": "Número de parcelas (cartão de crédito).",
            "format": "int32"
          },
          "cartaoBandeira": {
            "maxLength": 30,
            "type": "string",
            "description": "Bandeira do cartão.",
            "nullable": true
          },
          "cartaoNsu": {
            "maxLength": 20,
            "type": "string",
            "description": "NSU da transação de cartão.",
            "nullable": true
          },
          "cartaoAdquirente": {
            "maxLength": 30,
            "type": "string",
            "description": "Adquirente do cartão.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceResumo": {
        "required": [
          "numeroPedido",
          "situacao"
        ],
        "type": "object",
        "properties": {
          "numeroPedido": {
            "type": "string",
            "description": "Número do pedido na plataforma (o `numeroPedido` enviado no POST).",
            "nullable": true
          },
          "canal": {
            "type": "string",
            "description": "Canal de venda do pedido, como o integrador enviou (ex.: `ecommerce`, `marketplace`).",
            "nullable": true
          },
          "situacao": {
            "type": "string",
            "description": "recebido | aceito | emitidaNf | despachado | entregue | cancelado (pelo integrador) | rejeitado (pela loja).",
            "nullable": true
          },
          "recebidoEm": {
            "type": "string",
            "description": "Quando o pedido foi recebido pela loja.",
            "format": "date-time"
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração do pedido (aceite, NF-e, despacho e entrega contam; pedido cancelado ou rejeitado fica com o momento em que foi recebido) — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água do polling.",
            "format": "date-time",
            "nullable": true
          },
          "total": {
            "type": "number",
            "description": "Total do pedido gravado.",
            "format": "double",
            "nullable": true
          },
          "venda": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceVenda"
              }
            ],
            "description": "Venda gerada pela loja ao aceitar o pedido; ausente antes do aceite."
          },
          "notaFiscal": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceNotaFiscal"
              }
            ],
            "description": "Nota fiscal da venda; ausente antes da emissão."
          },
          "expedicao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PedidoEcommerceExpedicao"
              }
            ],
            "description": "Dados de despacho (rastreio). Omitido quando não há valor."
          },
          "entregueEm": {
            "type": "string",
            "description": "Data da entrega ao cliente (situação entregue).",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceTelefone": {
        "type": "object",
        "properties": {
          "primario": {
            "maxLength": 30,
            "type": "string",
            "description": "Telefone principal.",
            "nullable": true
          },
          "secundario": {
            "maxLength": 30,
            "type": "string",
            "description": "Telefone secundário.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceVenda": {
        "type": "object",
        "properties": {
          "numeroVenda": {
            "type": "integer",
            "description": "Número da venda gerada na loja.",
            "format": "int64"
          },
          "dataEncerramento": {
            "type": "string",
            "description": "Data e hora de encerramento da venda.",
            "format": "date-time",
            "nullable": true
          },
          "total": {
            "type": "number",
            "description": "Valor total da venda.",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "PedidoEcommerceVendedor": {
        "type": "object",
        "properties": {
          "id": {
            "maxLength": 14,
            "type": "string",
            "description": "CPF do vendedor (quando cadastrado na loja). Sem ele, o vendedor \"VENDEDOR ECOMMERCE\".",
            "nullable": true
          },
          "nome": {
            "maxLength": 250,
            "type": "string",
            "description": "Nome do vendedor.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "PingLeitura": {
        "required": [
          "integrador",
          "status"
        ],
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Sempre `ok` quando o token e a empresa são aceitos.",
            "nullable": true
          },
          "integrador": {
            "type": "string",
            "description": "Identificação do integrador (o `client_id` do token).",
            "nullable": true
          },
          "cnpj": {
            "type": "string",
            "description": "CNPJ da empresa informada em `empresaCnpj`, quando informado.",
            "nullable": true
          },
          "time": {
            "type": "string",
            "description": "Data e hora do servidor, no fuso da instalação.",
            "format": "date-time"
          }
        },
        "additionalProperties": false
      },
      "PrismaLeitura": {
        "type": "object",
        "properties": {
          "valor": {
            "type": "number",
            "description": "Valor do prisma (dioptrias prismáticas).",
            "format": "double",
            "nullable": true
          },
          "eixo": {
            "type": "integer",
            "description": "Eixo do prisma.",
            "format": "int32",
            "nullable": true
          },
          "angulo": {
            "type": "number",
            "description": "Ângulo do prisma.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ProblemDetails": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "nullable": true
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "integer",
            "format": "int32",
            "nullable": true
          },
          "detail": {
            "type": "string",
            "nullable": true
          },
          "instance": {
            "type": "string",
            "nullable": true
          },
          "code": {
            "type": "string",
            "description": "Código estável do erro, para tratar por programa (ex.: INVALID_PARAMS, EMPRESA_NAO_AUTORIZADA, RATE_LIMITED)."
          },
          "traceId": {
            "type": "string",
            "description": "Identificador da requisição — informe-o à Dataweb ao reportar um problema."
          },
          "correlationId": {
            "type": "string",
            "description": "Só no 500: correlação com o registro do erro no servidor."
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Só em erros de formato de parâmetro (binding): mensagens por parâmetro."
          }
        },
        "additionalProperties": { },
        "description": "Erro no formato RFC 9457 (application/problem+json)."
      },
      "ProdutoEcommerce": {
        "required": [
          "codItem",
          "descricao",
          "id"
        ],
        "type": "object",
        "properties": {
          "codItem": {
            "type": "string",
            "description": "Código do item no ERP — chave estável do produto e da ordem da paginação.",
            "nullable": true
          },
          "id": {
            "type": "string",
            "description": "Código externo (SKU) cadastrado no produto — o id usado nos itens do pedido.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do produto.",
            "nullable": true
          },
          "unidade": {
            "type": "string",
            "description": "Unidade de venda.",
            "nullable": true
          },
          "precoVenda": {
            "type": "number",
            "description": "Preço de venda.",
            "format": "double"
          },
          "peso": {
            "type": "number",
            "description": "Peso do produto. Omitido quando não há valor.",
            "format": "double",
            "nullable": true
          },
          "inclusao": {
            "type": "string",
            "description": "Data de cadastro do produto.",
            "format": "date",
            "nullable": true
          },
          "alteracao": {
            "type": "string",
            "description": "Data e hora da última alteração do produto (o mesmo valor de `alteradoEm`; mantido por compatibilidade).",
            "format": "date-time",
            "nullable": true
          },
          "alteradoEm": {
            "type": "string",
            "description": "Data e hora da última alteração do produto — o valor comparado por `alteradoEm[gte]`. Guarde o maior visto como marca d'água.",
            "format": "date-time",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceitaArmacaoLeitura": {
        "type": "object",
        "properties": {
          "codProduto": {
            "type": "string",
            "description": "Código do produto (armação) no ERP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição da armação.",
            "nullable": true
          },
          "referencia": {
            "type": "string",
            "description": "Referência da armação.",
            "nullable": true
          },
          "material": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CodigoDescricaoLeitura"
              }
            ],
            "description": "Material da armação."
          },
          "formatoAro": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CodigoDescricaoLeitura"
              }
            ],
            "description": "Formato do aro."
          },
          "ta": {
            "type": "number",
            "description": "Medida TA da armação (tamanho do aro, mm), como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "aa": {
            "type": "number",
            "description": "Medida AA da armação (altura do aro, mm), como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "md": {
            "type": "number",
            "description": "Medida MD da armação (maior diagonal, mm), como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "eixo": {
            "type": "number",
            "description": "Eixo da armação, como registrado na receita.",
            "format": "double",
            "nullable": true
          },
          "ponte": {
            "type": "number",
            "description": "Ponte da armação (mm).",
            "format": "double",
            "nullable": true
          },
          "diametro": {
            "type": "number",
            "description": "Diâmetro da lente (mm).",
            "format": "double",
            "nullable": true
          },
          "cvp": {
            "type": "string",
            "description": "Medida CVP, como registrada na receita.",
            "nullable": true
          },
          "distanciaLeitura": {
            "type": "number",
            "description": "Distância de leitura, como registrada na receita.",
            "format": "double",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceitaImagensLeitura": {
        "type": "object",
        "properties": {
          "receita": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ImagemLinkLeitura"
              }
            ],
            "description": "Imagem da receita (prescrição). Omitido quando não há valor."
          },
          "armacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ImagemLinkLeitura"
              }
            ],
            "description": "Imagem da armação. Omitido quando não há valor."
          },
          "armacaoAntiga": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ImagemLinkLeitura"
              }
            ],
            "description": "Imagem da armação antiga do cliente. Omitido quando não há valor."
          }
        },
        "additionalProperties": false
      },
      "ReceitaLeitura": {
        "required": [
          "cliente",
          "numeroOrdemServico"
        ],
        "type": "object",
        "properties": {
          "numeroOrdemServico": {
            "type": "integer",
            "description": "Número da O.S. da receita.",
            "format": "int32"
          },
          "dataPrescricao": {
            "type": "string",
            "description": "Data da prescrição médica (a validade é derivada dela; a base não a guarda).",
            "format": "date",
            "nullable": true
          },
          "dataInclusao": {
            "type": "string",
            "description": "Data em que a receita foi registrada na loja.",
            "format": "date",
            "nullable": true
          },
          "dataAviamento": {
            "type": "string",
            "description": "Data do aviamento (execução) da receita.",
            "format": "date",
            "nullable": true
          },
          "medico": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MedicoLeitura"
              }
            ],
            "description": "Médico prescritor. Omitido quando não há valor."
          },
          "paciente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PacienteLeitura"
              }
            ],
            "description": "Paciente da receita (pode ser diferente do cliente). Omitido quando não há valor."
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteResumoLeitura"
              }
            ],
            "description": "Cliente da O.S."
          },
          "olhoDominante": {
            "type": "string",
            "description": "direito | esquerdo; omitido quando não registrado.",
            "nullable": true
          },
          "dp": {
            "type": "number",
            "description": "Distância pupilar para longe (mm).",
            "format": "double",
            "nullable": true
          },
          "pertoDp": {
            "type": "number",
            "description": "Distância pupilar para perto (mm).",
            "format": "double",
            "nullable": true
          },
          "olhoDireito": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaOlhoLeitura"
              }
            ],
            "description": "Graus e medidas do olho direito; ausente quando a receita não tem a linha do olho."
          },
          "olhoEsquerdo": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaOlhoLeitura"
              }
            ],
            "description": "Graus e medidas do olho esquerdo; ausente quando a receita não tem a linha do olho."
          },
          "medidas": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaMedidasLeitura"
              }
            ],
            "description": "Medidas de montagem registradas na receita. Omitido quando não há valor."
          },
          "armacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaArmacaoLeitura"
              }
            ],
            "description": "Armação da receita e as medidas dela. Omitido quando não há valor."
          },
          "observacao": {
            "type": "string",
            "description": "Observação da receita.",
            "nullable": true
          },
          "imagens": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaImagensLeitura"
              }
            ],
            "description": "Links das imagens existentes; omitido quando a receita não tem nenhuma."
          }
        },
        "additionalProperties": false
      },
      "ReceitaLenteLeitura": {
        "type": "object",
        "properties": {
          "codProduto": {
            "type": "string",
            "description": "Código do produto (lente) no ERP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição da lente.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceitaMedidasLeitura": {
        "type": "object",
        "properties": {
          "distanciaVertice": {
            "type": "number",
            "description": "Distância vértice (mm).",
            "format": "double",
            "nullable": true
          },
          "distanciaProgressao": {
            "type": "number",
            "description": "Distância de progressão / corredor (mm).",
            "format": "double",
            "nullable": true
          },
          "anguloCurvatura": {
            "type": "number",
            "description": "Ângulo de curvatura da armação (graus).",
            "format": "double",
            "nullable": true
          },
          "anguloPantoscopico": {
            "type": "number",
            "description": "Ângulo pantoscópico (graus).",
            "format": "double",
            "nullable": true
          },
          "he": {
            "type": "number",
            "description": "Medida HE, como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "st": {
            "type": "number",
            "description": "Medida ST, como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "ca": {
            "type": "number",
            "description": "Medida CA, como registrada na receita.",
            "format": "double",
            "nullable": true
          },
          "vmap": {
            "type": "string",
            "description": "Código VMAP, como registrado na receita.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "ReceitaOlhoLeitura": {
        "type": "object",
        "properties": {
          "longe": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DioptriaLeitura"
              }
            ],
            "description": "Grau para longe; ausente sem grau."
          },
          "perto": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DioptriaLeitura"
              }
            ],
            "description": "Grau para perto; ausente em receita só para longe."
          },
          "adicao": {
            "type": "number",
            "description": "Adição do olho — a base guarda um único valor, válido para longe e perto.",
            "format": "double",
            "nullable": true
          },
          "altura": {
            "type": "number",
            "description": "Altura de montagem (mm).",
            "format": "double",
            "nullable": true
          },
          "dnp": {
            "type": "number",
            "description": "Distância naso-pupilar para longe (mm).",
            "format": "double",
            "nullable": true
          },
          "pertoDnp": {
            "type": "number",
            "description": "Distância naso-pupilar para perto (mm).",
            "format": "double",
            "nullable": true
          },
          "cro": {
            "type": "number",
            "description": "CRO do olho, como registrado na receita.",
            "format": "double",
            "nullable": true
          },
          "prisma1": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrismaLeitura"
              }
            ],
            "description": "Primeiro prisma do olho. Omitido quando não há valor."
          },
          "prisma2": {
            "allOf": [
              {
                "$ref": "#/components/schemas/PrismaLeitura"
              }
            ],
            "description": "Segundo prisma do olho. Omitido quando não há valor."
          },
          "lente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ReceitaLenteLeitura"
              }
            ],
            "description": "Lente indicada para o olho. Omitido quando não há valor."
          }
        },
        "additionalProperties": false
      },
      "VendaItemLeitura": {
        "type": "object",
        "properties": {
          "codItem": {
            "type": "string",
            "description": "Código do item no ERP.",
            "nullable": true
          },
          "descricao": {
            "type": "string",
            "description": "Descrição do item.",
            "nullable": true
          },
          "quantidade": {
            "type": "number",
            "description": "Quantidade.",
            "format": "double"
          },
          "valorUnitarioOriginal": {
            "type": "number",
            "description": "Preço unitário antes do desconto do item: o preço de tabela, ou o preço especial vigente quando o item entrou na venda (campanha, promoção).",
            "format": "double"
          },
          "valorUnitario": {
            "type": "number",
            "description": "Valor unitário praticado, já líquido do desconto do item.",
            "format": "double"
          },
          "desconto": {
            "type": "number",
            "description": "Desconto do item, em R$, na linha inteira: (valorUnitarioOriginal - valorUnitario) x quantidade, arredondado a 2 casas. Negativo = acréscimo (ex.: o acréscimo do cartão rateado pelo caixa).",
            "format": "double"
          },
          "total": {
            "type": "number",
            "description": "Valor total do item (líquido do desconto).",
            "format": "double"
          }
        },
        "additionalProperties": false
      },
      "VendaLeitura": {
        "required": [
          "codVenda",
          "itens"
        ],
        "type": "object",
        "properties": {
          "codVenda": {
            "type": "integer",
            "description": "Identificador da venda — use-o para identificar a venda (o `numeroVenda` pode se repetir entre vendas de uma mesma compra) e em `/vendas/{codVenda}`.",
            "format": "int32"
          },
          "numeroVenda": {
            "type": "integer",
            "description": "Número da venda no ERP (exibição). Duas vendas da mesma compra (ex.: O.S. e pronta entrega) podem ter o mesmo número.",
            "format": "int32",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data de emissão da venda (a data usada no recorte por período).",
            "format": "date",
            "nullable": true
          },
          "dataEncerramento": {
            "type": "string",
            "description": "Data de encerramento da venda.",
            "format": "date",
            "nullable": true
          },
          "total": {
            "type": "number",
            "description": "Valor total da venda.",
            "format": "double"
          },
          "totalProdutos": {
            "type": "number",
            "description": "Total dos produtos.",
            "format": "double"
          },
          "totalServicos": {
            "type": "number",
            "description": "Total dos serviços.",
            "format": "double"
          },
          "cliente": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ClienteDocumentoLeitura"
              }
            ],
            "description": "Cliente da venda: `null` quando NÃO identificado (venda sem CPF/CNPJ, ex.: NFC-e a consumidor não identificado) — o `null` sai explícito, nunca se infere \"não identificado\" pela ausência do campo."
          },
          "vendedor": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VendedorLeitura"
              }
            ],
            "description": "Vendedor da venda — o mesmo das telas do ERP."
          },
          "naturezaOperacao": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NaturezaOperacaoLeitura"
              }
            ],
            "description": "Natureza de operação como cadastrada na loja (5.102 venda, 5.922 simples faturamento, 5.910 bonificação/brinde…) — é por ela que o integrador separa brinde de receita."
          },
          "notaFiscal": {
            "allOf": [
              {
                "$ref": "#/components/schemas/NotaFiscalVendaLeitura"
              }
            ],
            "description": "Nota fiscal vinculada; ausente quando a venda não tem nota. Situação da NOTA, não da venda: venda cancelada é excluída do ERP e some da API."
          },
          "itens": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VendaItemLeitura"
            },
            "description": "Itens vendidos.",
            "nullable": true
          },
          "fatura": {
            "allOf": [
              {
                "$ref": "#/components/schemas/FaturaVendaLeitura"
              }
            ],
            "description": "`incluir=pagamentos`: a fatura da venda (os pagamentos pertencem a ela). Ausente sem o `incluir` ou quando a venda não tem fatura (ex.: bonificação)."
          },
          "pagamentos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PagamentoVendaLeitura"
            },
            "description": "`incluir=pagamentos`: parcelas da FATURA (compartilhadas pelas vendas de `fatura.vendas`). Ausente sem o `incluir`; `[]` quando pedido e não há.",
            "nullable": true
          },
          "convenios": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ConvenioVendaLeitura"
            },
            "description": "`incluir=pagamentos`: a parte da venda paga por convênio ou ticket — corre em PARALELO à fatura do cliente e NÃO entra em `pagamentos`. Ausente sem o `incluir`; `[]` quando pedido e não há.",
            "nullable": true
          },
          "devolucoes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DevolucaoRefLeitura"
            },
            "description": "`incluir=devolucoes`: referências das devoluções desta venda (detalhe em /devolucoes). Ausente sem o `incluir`; `[]` quando pedido e não há.",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "VendaOrigemLeitura": {
        "required": [
          "codVenda"
        ],
        "type": "object",
        "properties": {
          "codVenda": {
            "type": "integer",
            "description": "Identificador da venda devolvida (a chave de `/vendas/{codVenda}`).",
            "format": "int32"
          },
          "numeroVenda": {
            "type": "integer",
            "description": "Número da venda devolvida no ERP.",
            "format": "int32",
            "nullable": true
          },
          "dataEmissao": {
            "type": "string",
            "description": "Data de emissão da venda devolvida.",
            "format": "date",
            "nullable": true
          }
        },
        "additionalProperties": false
      },
      "VendedorLeitura": {
        "required": [
          "codigo"
        ],
        "type": "object",
        "properties": {
          "codigo": {
            "type": "integer",
            "description": "Código do vendedor no ERP (estável na instalação). O CPF do vendedor não é exposto.",
            "format": "int32"
          },
          "nome": {
            "type": "string",
            "description": "Nome do vendedor.",
            "nullable": true
          }
        },
        "additionalProperties": false
      }
    },
    "securitySchemes": {
      "oauth2": {
        "type": "oauth2",
        "description": "OAuth2 client_credentials: client_id e client_secret fornecidos pela Dataweb. O token vale 1 hora.",
        "flows": {
          "clientCredentials": {
            "tokenUrl": "/api/connect/token",
            "scopes": {
              "commercio.integracao.clientes:read": "Base de clientes: /clientes e /clientes/aniversariantes.",
              "commercio.integracao.ordens-servico:read": "Ordens de serviço: /ordens-servico e /ordens-servico/{numero}.",
              "commercio.integracao.ordens-servico.receita:read": "Receita óptica e imagens (dado de saúde) — exigido ALÉM de ordens-servico:read.",
              "commercio.integracao.vendas:read": "Vendas (com pagamentos) e devoluções: /vendas e /devolucoes.",
              "commercio.integracao.financeiro.contas-receber:read": "Contas a receber por documento do cliente: /financeiro/* (clientes, lançamentos, notas, XML/PDF, boleto).",
              "commercio.integracao.financeiro.cobranca:read": "Cobrança: vencidos de todos os clientes (/financeiro/cobranca/lancamentos) e os binários deles.",
              "commercio.integracao.ecommerce.pedidos:write": "E-commerce: gravar e cancelar pedidos.",
              "commercio.integracao.ecommerce.pedidos:read": "E-commerce: consultar os próprios pedidos.",
              "commercio.integracao.ecommerce.produtos:read": "E-commerce: catálogo de produtos.",
              "commercio.integracao.ecommerce.estoque:read": "E-commerce: saldo de estoque.",
              "commercio.integracao.dilab.ordens-servico:write": "Dilab: enviar e validar O.S. de laboratório (/dilab/ordens-servico) e ler os catálogos de serviços, materiais e formatos do aro.",
              "commercio.integracao.dilab.ordens-servico:read": "Dilab: consultar as próprias O.S. de laboratório, a situação (incl. recusa) e os catálogos de serviços, materiais e formatos do aro."
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Descoberta",
      "description": "Raiz autodescritiva, versão e o guia llms.txt (público)."
    },
    {
      "name": "Status",
      "description": "Teste de conectividade do token (e da empresa)."
    },
    {
      "name": "Empresas",
      "description": "Filiais liberadas para o token — o CNPJ usado em `empresaCnpj` em todo o resto."
    },
    {
      "name": "Clientes",
      "description": "Base de clientes (CRM): snapshot, delta por `alteradoEm[gte]` e aniversariantes."
    },
    {
      "name": "OrdensServico",
      "description": "Ordens de serviço: listagem com filtros e polling, detalhe, receita óptica e imagens."
    },
    {
      "name": "Vendas",
      "description": "Vendas encerradas, com vendedor, natureza, nota fiscal e — com `incluir` — pagamentos e devoluções."
    },
    {
      "name": "Devolucoes",
      "description": "Devoluções de venda (nota de entrada de devolução), com a venda de origem e o crédito gerado."
    },
    {
      "name": "Financeiro",
      "description": "Contas a receber por documento do cliente: parcelas, notas fiscais (XML/PDF) e boleto."
    },
    {
      "name": "Cobranca",
      "description": "Parcelas vencidas de todos os clientes das empresas autorizadas."
    },
    {
      "name": "EcommercePedidos",
      "description": "Pedidos de e-commerce gravados na loja: criação idempotente, consulta, polling e cancelamento."
    },
    {
      "name": "EcommerceProdutos",
      "description": "Catálogo e saldo de estoque para o integrador de e-commerce."
    },
    {
      "name": "DilabOrdensServico",
      "description": "O.S. de laboratório: envio (lente pela descrição), validação sem gravar, consulta, situação e recusa, e o catálogo de serviços."
    }
  ]
}