{
  "openapi": "3.0.3",
  "info": {
    "title": "PetroW — APIs de terceiro",
    "version": "1.0.0",
    "description": "APIs para integrar sistemas de terceiros (supervisório, balança, ERP, transportadora…) ao PetroW.\n\n**Autenticação**: todo pedido leva na query o identificador do perfil (`APP`, `REDE`, `CNPJ` ou `CPF`), a `SENHA` do dia e `A` (id do app). `SENHA = md5(identificador + AAAA-MM-DD + valor enviado em APP/REDE/CNPJ/CPF)`, com a data de Brasília (vale ontem, hoje e amanhã). O identificador é fornecido pela TX Fuel e deve ser guardado em segredo.\n\nManual completo: https://wiki.txfuel.com.br/pt-br/petrow/api",
    "contact": {
      "name": "Suporte TX Fuel",
      "email": "suporte@txfuel.com.br"
    }
  },
  "servers": [
    {
      "url": "https://pwbase1.txfuel.com.br/api",
      "description": "Servidor 1"
    },
    {
      "url": "https://pwbase2.txfuel.com.br/api",
      "description": "Servidor 2"
    }
  ],
  "tags": [
    {
      "name": "Ordens",
      "description": "Ordens de carregamento e descarregamento: criar, consultar, mudar a situação (fila, operação, finalizar), cancelar, lacres, amostras e conferência."
    },
    {
      "name": "Notas fiscais, CT-e e laudos",
      "description": "Consulta de notas fiscais e CT-e, pedido de importação pela chave, laudos de produto (com checklist) e movimento de saldo diário."
    },
    {
      "name": "Cadastros",
      "description": "Clientes, fornecedores, transportadoras, veículos, motoristas, produtos, pessoas, filiais, operadores e observações."
    },
    {
      "name": "Supervisório e automação",
      "description": "Usadas pelo programa Supervisório e pelos equipamentos da base: ordens do dia, senhas, eventos, tanques, peso de balança, cancela, câmera, totem, Dayler, Danload e impressão."
    }
  ],
  "security": [
    {
      "APP": [],
      "SENHA": [],
      "A": []
    },
    {
      "REDE": [],
      "SENHA": [],
      "A": []
    },
    {
      "CNPJ": [],
      "SENHA": [],
      "A": []
    },
    {
      "CPF": [],
      "SENHA": [],
      "A": []
    }
  ],
  "components": {
    "securitySchemes": {
      "APP": {
        "type": "apiKey",
        "in": "query",
        "name": "APP",
        "description": "Nome do app (perfil App) — use um entre APP, REDE, CNPJ e CPF"
      },
      "REDE": {
        "type": "apiKey",
        "in": "query",
        "name": "REDE",
        "description": "Nome da rede (perfil Rede)"
      },
      "CNPJ": {
        "type": "apiKey",
        "in": "query",
        "name": "CNPJ",
        "description": "CNPJ da filial ou do cliente, só números (perfis Filial e Cliente)"
      },
      "CPF": {
        "type": "apiKey",
        "in": "query",
        "name": "CPF",
        "description": "CPF, só números"
      },
      "SENHA": {
        "type": "apiKey",
        "in": "query",
        "name": "SENHA",
        "description": "md5(identificador + AAAA-MM-DD + valor de APP/REDE/CNPJ/CPF)"
      },
      "A": {
        "type": "apiKey",
        "in": "query",
        "name": "A",
        "description": "Id do app no PetroW"
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "error"
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "example": {
              "id_ordem": "Valor inválido"
            }
          }
        }
      }
    },
    "responses": {
      "Erro400": {
        "description": "Dados inválidos ou regra de negócio",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Erro"
            }
          }
        }
      },
      "Erro401": {
        "description": "Identificador, senha ou app inválidos",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Erro"
            },
            "example": {
              "status": "error",
              "errors": {
                "error": "Não autorizada!"
              }
            }
          }
        }
      },
      "Erro403": {
        "description": "Perfil sem permissão para este método, ou registro fora do escopo do identificador",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Erro"
            },
            "example": {
              "status": "error",
              "errors": {
                "acesso": "Negado"
              }
            }
          }
        }
      },
      "Erro405": {
        "description": "Método não implementado neste endpoint"
      }
    }
  },
  "paths": {
    "/v1/terceiro/ordem": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Ordem pelo id",
        "description": "Verifica o tipo da ordem e devolve exatamente a mesma resposta de GET ordemCarregamento (tipo C) ou GET ordemDescarregamento (tipo D). Só aceita GET.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_ordem",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123456,
                  "tipo": "C",
                  "id_cliente": 101,
                  "id_motorista": 2001,
                  "id_fornecedor": 0,
                  "id_veiculo1": 3001,
                  "id_veiculo2": 3002,
                  "id_veiculo3": 0,
                  "id_veiculo4": 0,
                  "id_transportadora": 401,
                  "id_operador": 0,
                  "validade_inicial": "2026-11-12 00:00:00",
                  "validade_final": "2026-11-13 23:59:59",
                  "situacao": "P",
                  "data_hora_pendente": "2026-11-12 08:00:00",
                  "data_hora_aguardando": null,
                  "data_hora_operacao": null,
                  "data_hora_finalizada": null,
                  "data_hora_cancelada": null,
                  "transferencia": "N",
                  "congenere": "N",
                  "ajuste": "N",
                  "vazio_balanca": 0,
                  "cheio_balanca": 0,
                  "modal": "R",
                  "data_hora_vistoria": null,
                  "vistoria": "N",
                  "metodo": "",
                  "codigo_interno": "OC-0001",
                  "id_nota_fiscal": 0,
                  "observacao": "",
                  "data_hora_apuracao": null,
                  "data_hora_conferencia": null,
                  "tarifar": "S",
                  "numero": 98765,
                  "ordem_item": [
                    {
                      "id_ordem_item": 1,
                      "id_veiculo": 3002,
                      "compartimento": 1,
                      "nivel": 0,
                      "sequencia": 0,
                      "id_operador": 0,
                      "amostras": 0,
                      "id_produto": 10,
                      "quantidade": 10000.0,
                      "temperatura": 0,
                      "densidade": 0,
                      "fator_de_correcao": 0,
                      "quantidade_a_20": 0,
                      "massa": 0,
                      "inpm": 0,
                      "gl": 0,
                      "densidade_a_20": 0,
                      "composicao": [
                        {
                          "id_produto": 10,
                          "percentual": 100,
                          "quantidade_ambiente": 10000.0,
                          "quantidade_a_20": 0.0,
                          "temperatura": 0,
                          "densidade": 0,
                          "densidade_a_20": 0,
                          "fator_de_correcao": 0,
                          "massa": 0
                        }
                      ],
                      "apuracao": {
                        "quantidade_ambiente": 10000.0,
                        "quantidade_a_20": 0,
                        "massa": 0,
                        "temperatura": 0,
                        "densidade": 0,
                        "densidade_a_20": 0,
                        "fator_de_correcao": 0
                      }
                    }
                  ],
                  "ordem_produto": [
                    {
                      "id_ordem_produto": 1,
                      "id_produto": 10,
                      "id_laudo_produto": 0,
                      "quantidade_ambiente": 10000,
                      "quantidade_a_20": 0,
                      "temperatura": 0,
                      "densidade": 0,
                      "fator_de_correcao": 0,
                      "massa": 0,
                      "densidade_a_20": 0,
                      "quantidade_a_20_apurado": 0,
                      "quantidade_encerrante": 0,
                      "inpm": 0,
                      "gl": 0
                    }
                  ],
                  "ordem_senha": [
                    {
                      "compartimento": 1,
                      "sequencia": 0,
                      "senha": "1234"
                    }
                  ],
                  "ordem_situacao": [
                    {
                      "id_ordem_situacao": 1,
                      "situacao": "P",
                      "data_hora": "2026-11-12 08:00:00",
                      "id_tx_pessoa": 0
                    }
                  ],
                  "ordem_lacre": [
                    {
                      "tipo": "SUPERIOR",
                      "numero": 1001
                    }
                  ],
                  "ordem_amostra": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/ordemCarregamento": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Consulta a ordem de carregamento",
        "description": "Datas no formato ISO 'AAAA-MM-DDTHH:MM:SS.ffffff' (segundos e frações omitidos quando zero). 1980-01-01T00:00 = sem data; 2099-12-31T23:59(:59) = sem limite.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_ordemCarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123456,
                  "tipo": "C",
                  "id_cliente": 101,
                  "id_motorista": 2001,
                  "id_fornecedor": 0,
                  "id_veiculo1": 3001,
                  "id_veiculo2": 3002,
                  "id_veiculo3": 0,
                  "id_veiculo4": 0,
                  "id_transportadora": 401,
                  "id_operador": 0,
                  "validade_inicial": "2026-11-12 00:00:00",
                  "validade_final": "2026-11-13 23:59:59",
                  "situacao": "P",
                  "data_hora_pendente": "2026-11-12 08:00:00",
                  "data_hora_aguardando": null,
                  "data_hora_operacao": null,
                  "data_hora_finalizada": null,
                  "data_hora_cancelada": null,
                  "transferencia": "N",
                  "congenere": "N",
                  "ajuste": "N",
                  "vazio_balanca": 0,
                  "cheio_balanca": 0,
                  "modal": "R",
                  "data_hora_vistoria": null,
                  "vistoria": "N",
                  "metodo": "",
                  "codigo_interno": "OC-0001",
                  "id_nota_fiscal": 0,
                  "observacao": "",
                  "data_hora_apuracao": null,
                  "data_hora_conferencia": null,
                  "tarifar": "S",
                  "numero": 98765,
                  "ordem_item": [
                    {
                      "id_ordem_item": 1,
                      "id_veiculo": 3002,
                      "compartimento": 1,
                      "nivel": 0,
                      "sequencia": 0,
                      "id_operador": 0,
                      "amostras": 0,
                      "id_produto": 10,
                      "quantidade": 10000.0,
                      "temperatura": 0,
                      "densidade": 0,
                      "fator_de_correcao": 0,
                      "quantidade_a_20": 0,
                      "massa": 0,
                      "inpm": 0,
                      "gl": 0,
                      "densidade_a_20": 0,
                      "composicao": [
                        {
                          "id_produto": 10,
                          "percentual": 100,
                          "quantidade_ambiente": 10000.0,
                          "quantidade_a_20": 0.0,
                          "temperatura": 0,
                          "densidade": 0,
                          "densidade_a_20": 0,
                          "fator_de_correcao": 0,
                          "massa": 0
                        }
                      ],
                      "apuracao": {
                        "quantidade_ambiente": 10000.0,
                        "quantidade_a_20": 0,
                        "massa": 0,
                        "temperatura": 0,
                        "densidade": 0,
                        "densidade_a_20": 0,
                        "fator_de_correcao": 0
                      }
                    }
                  ],
                  "ordem_produto": [
                    {
                      "id_ordem_produto": 1,
                      "id_produto": 10,
                      "id_laudo_produto": 0,
                      "quantidade_ambiente": 10000,
                      "quantidade_a_20": 0,
                      "temperatura": 0,
                      "densidade": 0,
                      "fator_de_correcao": 0,
                      "massa": 0,
                      "densidade_a_20": 0,
                      "quantidade_a_20_apurado": 0,
                      "quantidade_encerrante": 0,
                      "inpm": 0,
                      "gl": 0
                    }
                  ],
                  "ordem_senha": [
                    {
                      "compartimento": 1,
                      "sequencia": 0,
                      "senha": "1234"
                    }
                  ],
                  "ordem_situacao": [
                    {
                      "id_ordem_situacao": 1,
                      "situacao": "P",
                      "data_hora": "2026-11-12 08:00:00",
                      "id_tx_pessoa": 0
                    }
                  ],
                  "ordem_lacre": [
                    {
                      "tipo": "SUPERIOR",
                      "numero": 1001
                    }
                  ],
                  "ordem_amostra": []
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Ordens"
        ],
        "summary": "Cria ordem de carregamento",
        "description": "POST cria a ordem de carregamento com os itens (compartimentos) e, se enviados, lacres, amostras e laudos, tudo de uma vez: se algo falhar, nada é gravado. PUT muda a situação (?acao=FILA|OPERACAO|FINALIZAR|CANCELAR) ou, se o corpo trouxer laudo_produto, só vincula ou remove laudos. DELETE cancela, apenas ordem em P (pendente). Acesso com perfil filial cria a ordem na própria filial; acesso com perfil cliente só cria e consulta ordens do próprio cliente.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_ordemCarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id_cliente": {
                    "type": "integer",
                    "description": "Cliente da ordem. Alternativa: cpf_cnpj_cliente. Se o terceiro é de um cliente, a ordem vai sempre para esse cliente (informar outro dá 403)."
                  },
                  "cpf_cnpj_cliente": {
                    "type": "string",
                    "description": "CPF/CNPJ do cliente (só números ou formatado). Usado quando id_cliente vem vazio ou 0."
                  },
                  "id_motorista": {
                    "type": "integer",
                    "description": "Alternativa: cpf_motorista."
                  },
                  "cpf_motorista": {
                    "type": "string",
                    "description": "CPF do motorista."
                  },
                  "id_fornecedor": {
                    "type": "integer",
                    "description": "Alternativa: cpf_cnpj_fornecedor."
                  },
                  "cpf_cnpj_fornecedor": {
                    "type": "string"
                  },
                  "id_veiculo1": {
                    "type": "integer",
                    "description": "Veículo 1 (cavalo). Alternativa: placa1."
                  },
                  "placa1": {
                    "type": "string",
                    "description": "Placa do veículo 1 (precisa ser uma placa válida)."
                  },
                  "id_veiculo2": {
                    "type": "integer",
                    "description": "Alternativa: placa2."
                  },
                  "placa2": {
                    "type": "string"
                  },
                  "id_veiculo3": {
                    "type": "integer",
                    "description": "Alternativa: placa3."
                  },
                  "placa3": {
                    "type": "string"
                  },
                  "id_veiculo4": {
                    "type": "integer",
                    "description": "Alternativa: placa4."
                  },
                  "placa4": {
                    "type": "string"
                  },
                  "id_transportadora": {
                    "type": "integer",
                    "description": "Alternativa: cpf_cnpj_transportadora."
                  },
                  "cpf_cnpj_transportadora": {
                    "type": "string"
                  },
                  "transferencia": {
                    "type": "boolean",
                    "description": "true = transferência (grava S). Padrão: false (N)."
                  },
                  "validade_inicial": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Texto 'AAAA-MM-DD HH:MM:SS' (precisa ter 14 dígitos). Formato diferente é ignorado e o campo fica vazio."
                  },
                  "validade_final": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Idem."
                  },
                  "codigo_interno": {
                    "type": "string",
                    "description": "Código da ordem no sistema do integrador."
                  },
                  "observacao": {
                    "type": "string"
                  },
                  "nfe_origem": {
                    "type": "string"
                  },
                  "cte_origem": {
                    "type": "string"
                  },
                  "ordem_item": {
                    "type": "array",
                    "items": {},
                    "description": "Obrigatório, com pelo menos 1 item. Cada item: id_veiculo (ou placa), id_produto (só o id), compartimento (inteiro, padrão 0), nivel (inteiro, padrão 0), quantidade (litros, inteiro, padrão 0) e amostras (inteiro, padrão 0). A sequencia é a posição do item na lista (0, 1, …). O servidor calcula os totais por produto (ordem_produto) a partir dos itens."
                  },
                  "ordem_lacre": {
                    "type": "array",
                    "items": {},
                    "description": "Opcional: [{tipo (texto), numero (inteiro maior que 0; aceita 1001 ou \"1001\")}]. Lacre repetido na lista é recusado (400)."
                  },
                  "ordem_amostra": {
                    "type": "array",
                    "items": {},
                    "description": "Opcional, mesmo formato de ordem_lacre. O par (tipo, numero) da amostra não pode se repetir na lista nem em outra ordem (400)."
                  },
                  "laudo_produto": {
                    "type": "array",
                    "items": {},
                    "description": "Opcional: [{id_produto, id_laudo_produto}]. Vincula o laudo ao produto da ordem; id_laudo_produto = 0 remove. Produto que não está na ordem dá erro."
                  }
                },
                "required": [
                  "ordem_item"
                ]
              },
              "example": {
                "cpf_cnpj_cliente": "00.000.000/0001-00",
                "cpf_motorista": "000.000.000-00",
                "placa1": "ABC1D23",
                "placa2": "ABC1D24",
                "cpf_cnpj_transportadora": "00.000.000/0002-00",
                "transferencia": false,
                "validade_inicial": "2026-11-12 00:00:00",
                "validade_final": "2026-11-13 23:59:59",
                "codigo_interno": "OC-0001",
                "observacao": "",
                "ordem_item": [
                  {
                    "placa": "ABC1D24",
                    "id_produto": 10,
                    "compartimento": 1,
                    "nivel": 0,
                    "quantidade": 10000,
                    "amostras": 0
                  },
                  {
                    "placa": "ABC1D24",
                    "id_produto": 10,
                    "compartimento": 2,
                    "nivel": 0,
                    "quantidade": 15000,
                    "amostras": 0
                  }
                ],
                "ordem_lacre": [
                  {
                    "tipo": "SUPERIOR",
                    "numero": "1001"
                  }
                ],
                "ordem_amostra": [
                  {
                    "tipo": "TESTEMUNHA",
                    "numero": "5001"
                  }
                ],
                "laudo_produto": [
                  {
                    "id_produto": 10,
                    "id_laudo_produto": 77
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123456
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Ordens"
        ],
        "summary": "Muda a situação (acao) ou vincula/remove laudos por produto",
        "description": "FILA, OPERACAO e FINALIZAR não verificam se a ordem é de carregamento (só CANCELAR verifica o tipo). FILA e OPERACAO fora da situação esperada respondem 200 com situacao='ORDEM NÃO ENCONTRADA', e não um erro.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `FILA`: Põe a ordem na fila. Só age se a ordem estiver em P (pendente) e for do app; caso contrário, responde 200 com situacao='ORDEM NÃO ENCONTRADA'. Sucesso: situacao='ORDEM INCLUÍDA NA FILA' + id_ordem, tipo, id_cliente, cliente, id_veiculo, veiculo, id_motorista, motorista, produtos. Pendência de documento ou de agendamento: 400 com {\"errors\":{\"exception\": …}} e, quando houver, situacao='ORDEM C/ PENDÊNCIAS' + pendencias[].\n- `OPERACAO`: Passa a ordem para O (operação), com data_hora_operacao = agora. Só age se a ordem estiver em A (aguardando); caso contrário, responde 200 com situacao='ORDEM NÃO ENCONTRADA'. No carregamento, preenche a temperatura e a densidade padrão do cliente para o produto (por produto ou por item, conforme o parâmetro ORDEM_PRODUTO_PREENCHER_TEMP_DENS) e recalcula os volumes. Sucesso: situacao='ORDEM INCLUÍDA NA OPERAÇÃO' + os mesmos campos da ação FILA.\n- `FINALIZAR`: Finaliza a ordem (ordens de equipamentos Dayler são processadas antes). Pode ser repetida: ordem já finalizada responde situacao='ORDEM FINALIZADA'. Se o app exige conferência (parâmetro OPERACAO_CARREGAMENTO_CONFERENCIA ou OPERACAO_DESCARREGAMENTO_CONFERENCIA = S) e a ordem não foi conferida: 400 'Falha ao finalizar: Conferência não realizada'. Outras falhas (ex. bloqueio de temperatura): 400 com {\"errors\":{\"ordem\": …}} e situacao='ORDEM NÃO FINALIZADA'. Esta ação não exige uma situação de origem específica.\n- `CANCELAR`: Igual ao DELETE: cancela apenas ordem em P (pendente) e do tipo do endpoint.",
        "operationId": "put_ordemCarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          },
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "FILA, OPERACAO, FINALIZAR ou CANCELAR. Obrigatória, exceto quando o corpo traz laudo_produto."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "laudo_produto": {
                    "type": "array",
                    "items": {},
                    "description": "[{id_produto, id_laudo_produto}]: vincula o laudo ao produto da ordem; id_laudo_produto = 0 remove. Quando presente, o PUT faz só isso e ignora acao."
                  }
                }
              },
              "example": {
                "laudo_produto": [
                  {
                    "id_produto": 10,
                    "id_laudo_produto": 77
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "situacao": "ORDEM INCLUÍDA NA FILA",
                  "id_ordem": 123456,
                  "tipo": "C",
                  "id_cliente": 101,
                  "cliente": "CLIENTE EXEMPLO",
                  "id_veiculo": 3001,
                  "veiculo": "ABC1D23",
                  "id_motorista": 2001,
                  "motorista": "MOTORISTA 01",
                  "produtos": "DIESEL S10"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Ordens"
        ],
        "summary": "Cancela a ordem (só em P, pendente)",
        "description": "POST cria a ordem de carregamento com os itens (compartimentos) e, se enviados, lacres, amostras e laudos, tudo de uma vez: se algo falhar, nada é gravado. PUT muda a situação (?acao=FILA|OPERACAO|FINALIZAR|CANCELAR) ou, se o corpo trouxer laudo_produto, só vincula ou remove laudos. DELETE cancela, apenas ordem em P (pendente). Acesso com perfil filial cria a ordem na própria filial; acesso com perfil cliente só cria e consulta ordens do próprio cliente.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "delete_ordemCarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123456,
                  "situacao": "C"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/ordemDescarregamento": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Consulta a ordem de descarregamento",
        "description": "POST cria a ordem de descarregamento (um produto, volumes da nota de remessa e laudo opcional). Ao contrário do carregamento, não tem itens nem compartimentos: o POST ignora ordem_item, ordem_lacre, ordem_amostra e transferencia (lacres e amostras vão por ordemLacre e ordemAmostra). PUT muda a situação por ?acao= ou, com ?id_laudo_produto=, só vincula ou remove o laudo. DELETE cancela apenas ordem em P (pendente).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_ordemDescarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123457,
                  "tipo": "D",
                  "id_cliente": 101,
                  "id_motorista": 2001,
                  "id_fornecedor": 0,
                  "id_veiculo1": 3001,
                  "id_veiculo2": 0,
                  "id_veiculo3": 0,
                  "id_veiculo4": 0,
                  "id_transportadora": 401,
                  "id_operador": 0,
                  "validade_inicial": "2026-11-12 00:00:00",
                  "validade_final": "2026-11-13 23:59:59",
                  "situacao": "P",
                  "data_hora_pendente": "2026-11-12 08:00:00",
                  "id_produto": 10,
                  "volume_ambiente_remessa": 30000,
                  "volume_a_20_remessa": 29850,
                  "densidade_a_20_remessa": 0.835,
                  "volume_ambiente": 30000,
                  "volume_a_20": 0,
                  "codigo_interno": "OC-0002",
                  "nfe_origem": "",
                  "cte_origem": "",
                  "id_laudo_produto": 0,
                  "numero": 98766,
                  "ordem_senha": [],
                  "ordem_situacao": [
                    {
                      "id_ordem_situacao": 2,
                      "situacao": "P",
                      "data_hora": "2026-11-12 08:00:00",
                      "id_tx_pessoa": 0
                    }
                  ],
                  "...": "demais campos de resposta_campos"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Ordens"
        ],
        "summary": "Cria ordem de descarregamento",
        "description": "POST cria a ordem de descarregamento (um produto, volumes da nota de remessa e laudo opcional). Ao contrário do carregamento, não tem itens nem compartimentos: o POST ignora ordem_item, ordem_lacre, ordem_amostra e transferencia (lacres e amostras vão por ordemLacre e ordemAmostra). PUT muda a situação por ?acao= ou, com ?id_laudo_produto=, só vincula ou remove o laudo. DELETE cancela apenas ordem em P (pendente).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_ordemDescarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id_cliente": {
                    "type": "integer",
                    "description": "Alternativa: cpf_cnpj_cliente. Se o terceiro é de um cliente, a ordem vai sempre para esse cliente (informar outro dá 403)."
                  },
                  "cpf_cnpj_cliente": {
                    "type": "string"
                  },
                  "id_motorista": {
                    "type": "integer",
                    "description": "Alternativa: cpf_motorista."
                  },
                  "cpf_motorista": {
                    "type": "string"
                  },
                  "id_fornecedor": {
                    "type": "integer",
                    "description": "Alternativa: cpf_cnpj_fornecedor."
                  },
                  "cpf_cnpj_fornecedor": {
                    "type": "string"
                  },
                  "id_veiculo1": {
                    "type": "integer",
                    "description": "Alternativa: placa1."
                  },
                  "placa1": {
                    "type": "string"
                  },
                  "id_veiculo2": {
                    "type": "integer",
                    "description": "Alternativa: placa2."
                  },
                  "placa2": {
                    "type": "string"
                  },
                  "id_veiculo3": {
                    "type": "integer",
                    "description": "Alternativa: placa3."
                  },
                  "placa3": {
                    "type": "string"
                  },
                  "id_veiculo4": {
                    "type": "integer",
                    "description": "Alternativa: placa4."
                  },
                  "placa4": {
                    "type": "string"
                  },
                  "id_transportadora": {
                    "type": "integer",
                    "description": "Alternativa: cpf_cnpj_transportadora."
                  },
                  "cpf_cnpj_transportadora": {
                    "type": "string"
                  },
                  "id_produto": {
                    "type": "integer",
                    "description": "Produto descarregado (só o id; não há alternativa por código)."
                  },
                  "validade_inicial": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Texto 'AAAA-MM-DD HH:MM:SS'."
                  },
                  "validade_final": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Texto 'AAAA-MM-DD HH:MM:SS'."
                  },
                  "volume_a_20_remessa": {
                    "type": "number",
                    "description": "Volume a 20 °C da nota de remessa (L)."
                  },
                  "volume_ambiente_remessa": {
                    "type": "number",
                    "description": "Volume ambiente da remessa (L). Também preenche volume_ambiente."
                  },
                  "densidade_a_20_remessa": {
                    "type": "number"
                  },
                  "codigo_interno": {
                    "type": "string"
                  },
                  "observacao": {
                    "type": "string"
                  },
                  "nfe_origem": {
                    "type": "string"
                  },
                  "cte_origem": {
                    "type": "string"
                  },
                  "id_laudo_produto": {
                    "type": "integer",
                    "description": "Laudo a vincular à ordem (> 0)."
                  }
                }
              },
              "example": {
                "cpf_cnpj_cliente": "00.000.000/0001-00",
                "cpf_motorista": "000.000.000-00",
                "placa1": "ABC1D23",
                "id_produto": 10,
                "volume_ambiente_remessa": 30000,
                "volume_a_20_remessa": 29850,
                "densidade_a_20_remessa": 0.835,
                "codigo_interno": "OC-0002",
                "nfe_origem": "00000000000000000000000000000000000000000000",
                "id_laudo_produto": 77
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123457
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Ordens"
        ],
        "summary": "Muda a situação (acao) ou vincula/remove o laudo",
        "description": "O PUT do descarregamento não lê o corpo: o laudo vai na query (no carregamento, vai no corpo). FILA, OPERACAO e FINALIZAR não verificam o tipo da ordem.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `FILA`: Põe a ordem na fila. Só age se a ordem estiver em P (pendente) e for do app; caso contrário, responde 200 com situacao='ORDEM NÃO ENCONTRADA'. Sucesso: situacao='ORDEM INCLUÍDA NA FILA' + id_ordem, tipo, id_cliente, cliente, id_veiculo, veiculo, id_motorista, motorista, produtos. Pendência de documento ou de agendamento: 400 com {\"errors\":{\"exception\": …}} e, quando houver, situacao='ORDEM C/ PENDÊNCIAS' + pendencias[].\n- `OPERACAO`: Passa a ordem para O (operação), com data_hora_operacao = agora. Só age se a ordem estiver em A (aguardando); caso contrário, responde 200 com situacao='ORDEM NÃO ENCONTRADA'. No carregamento, preenche a temperatura e a densidade padrão do cliente para o produto (por produto ou por item, conforme o parâmetro ORDEM_PRODUTO_PREENCHER_TEMP_DENS) e recalcula os volumes. Sucesso: situacao='ORDEM INCLUÍDA NA OPERAÇÃO' + os mesmos campos da ação FILA.\n- `FINALIZAR`: Finaliza a ordem (ordens de equipamentos Dayler são processadas antes). Pode ser repetida: ordem já finalizada responde situacao='ORDEM FINALIZADA'. Se o app exige conferência (parâmetro OPERACAO_CARREGAMENTO_CONFERENCIA ou OPERACAO_DESCARREGAMENTO_CONFERENCIA = S) e a ordem não foi conferida: 400 'Falha ao finalizar: Conferência não realizada'. Outras falhas (ex. bloqueio de temperatura): 400 com {\"errors\":{\"ordem\": …}} e situacao='ORDEM NÃO FINALIZADA'. Esta ação não exige uma situação de origem específica.\n- `CANCELAR`: Igual ao DELETE: cancela apenas ordem em P (pendente) e do tipo do endpoint.",
        "operationId": "put_ordemDescarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          },
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "FILA, OPERACAO, FINALIZAR ou CANCELAR. Obrigatória, exceto quando se informa id_laudo_produto."
          },
          {
            "name": "id_laudo_produto",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Se informado (>= 0), o PUT faz só isso e ignora acao: > 0 vincula o laudo à ordem; 0 remove o laudo."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "situacao": "ORDEM INCLUÍDA NA OPERAÇÃO",
                  "id_ordem": 123457,
                  "tipo": "D",
                  "id_cliente": 101,
                  "cliente": "CLIENTE EXEMPLO",
                  "id_veiculo": 3001,
                  "veiculo": "ABC1D23",
                  "id_motorista": 2001,
                  "motorista": "MOTORISTA 01",
                  "produtos": "ETANOL"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Ordens"
        ],
        "summary": "Cancela a ordem (só em P, pendente)",
        "description": "POST cria a ordem de descarregamento (um produto, volumes da nota de remessa e laudo opcional). Ao contrário do carregamento, não tem itens nem compartimentos: o POST ignora ordem_item, ordem_lacre, ordem_amostra e transferencia (lacres e amostras vão por ordemLacre e ordemAmostra). PUT muda a situação por ?acao= ou, com ?id_laudo_produto=, só vincula ou remove o laudo. DELETE cancela apenas ordem em P (pendente).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "delete_ordemDescarregamento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_ordem": 123457,
                  "situacao": "C"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/ordemLacre": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Lista os lacres da ordem",
        "description": "Consulta e mantém os lacres de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove um lacre ou todos. O mesmo lacre não pode se repetir na mesma ordem (pode existir em outras).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_ordemLacre",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "tipo": "SUPERIOR",
                      "numero": 1001
                    }
                  ],
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Ordens"
        ],
        "summary": "Acrescenta lacres (sem apagar os existentes)",
        "description": "Consulta e mantém os lacres de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove um lacre ou todos. O mesmo lacre não pode se repetir na mesma ordem (pode existir em outras).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_ordemLacre",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "tipo": {
                      "type": "string",
                      "description": "Tipo do lacre (texto livre, ex. SUPERIOR)."
                    },
                    "numero": {
                      "type": "integer",
                      "description": "Número (inteiro maior que 0). Aceita número ou texto só com dígitos (1001 ou \"1001\")."
                    }
                  },
                  "required": [
                    "tipo",
                    "numero"
                  ]
                }
              },
              "example": [
                {
                  "tipo": "SUPERIOR",
                  "numero": 1001
                },
                {
                  "tipo": "INFERIOR",
                  "numero": 1002
                }
              ]
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Ordens"
        ],
        "summary": "Substitui todos os lacres da ordem pela lista enviada",
        "description": "Consulta e mantém os lacres de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove um lacre ou todos. O mesmo lacre não pode se repetir na mesma ordem (pode existir em outras).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_ordemLacre",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "tipo": {
                      "type": "string",
                      "description": "Tipo do lacre (texto livre, ex. SUPERIOR)."
                    },
                    "numero": {
                      "type": "integer",
                      "description": "Número (inteiro maior que 0). Aceita número ou texto só com dígitos (1001 ou \"1001\")."
                    }
                  },
                  "required": [
                    "tipo",
                    "numero"
                  ]
                }
              },
              "example": [
                {
                  "tipo": "SUPERIOR",
                  "numero": 1001
                },
                {
                  "tipo": "INFERIOR",
                  "numero": 1002
                }
              ]
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Ordens"
        ],
        "summary": "Remove um lacre (tipo+numero) ou todos (sem os dois)",
        "description": "Consulta e mantém os lacres de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove um lacre ou todos. O mesmo lacre não pode se repetir na mesma ordem (pode existir em outras).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "delete_ordemLacre",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Tipo do item a remover. Vai junto com numero; sem os dois, remove todos."
          },
          {
            "name": "numero",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Número do item a remover."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "removidos": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/ordemAmostra": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Lista as amostras da ordem",
        "description": "Consulta e mantém as amostras de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove uma amostra ou todas. O par (tipo, numero) da amostra é único em todas as ordens: o POST avisa se a amostra já está nesta ou em outra ordem.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_ordemAmostra",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "tipo": "SUPERIOR",
                      "numero": 1001
                    }
                  ],
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Ordens"
        ],
        "summary": "Acrescenta amostras (sem apagar as existentes)",
        "description": "Consulta e mantém as amostras de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove uma amostra ou todas. O par (tipo, numero) da amostra é único em todas as ordens: o POST avisa se a amostra já está nesta ou em outra ordem.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_ordemAmostra",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "tipo": {
                      "type": "string",
                      "description": "Tipo da amostra (texto livre, ex. SUPERIOR)."
                    },
                    "numero": {
                      "type": "integer",
                      "description": "Número (inteiro maior que 0). Aceita número ou texto só com dígitos (1001 ou \"1001\")."
                    }
                  },
                  "required": [
                    "tipo",
                    "numero"
                  ]
                }
              },
              "example": [
                {
                  "tipo": "SUPERIOR",
                  "numero": 1001
                },
                {
                  "tipo": "INFERIOR",
                  "numero": 1002
                }
              ]
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Ordens"
        ],
        "summary": "Substitui todas as amostras da ordem pela lista enviada",
        "description": "Consulta e mantém as amostras de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove uma amostra ou todas. O par (tipo, numero) da amostra é único em todas as ordens: o POST avisa se a amostra já está nesta ou em outra ordem.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_ordemAmostra",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "tipo": {
                      "type": "string",
                      "description": "Tipo da amostra (texto livre, ex. SUPERIOR)."
                    },
                    "numero": {
                      "type": "integer",
                      "description": "Número (inteiro maior que 0). Aceita número ou texto só com dígitos (1001 ou \"1001\")."
                    }
                  },
                  "required": [
                    "tipo",
                    "numero"
                  ]
                }
              },
              "example": [
                {
                  "tipo": "SUPERIOR",
                  "numero": 1001
                },
                {
                  "tipo": "INFERIOR",
                  "numero": 1002
                }
              ]
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Ordens"
        ],
        "summary": "Remove uma amostra (tipo + numero) ou todas (sem os dois)",
        "description": "Consulta e mantém as amostras de uma ordem (carregamento ou descarregamento). POST, PUT e DELETE só funcionam com a ordem em P (pendente) e dentro do escopo do acesso. POST acrescenta, PUT substitui a lista inteira e DELETE remove uma amostra ou todas. O par (tipo, numero) da amostra é único em todas as ordens: o POST avisa se a amostra já está nesta ou em outra ordem.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "delete_ordemAmostra",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Tipo do item a remover. Vai junto com numero; sem os dois, remove todos."
          },
          {
            "name": "numero",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Número do item a remover."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "removidos": 1
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/conferencia": {
      "get": {
        "tags": [
          "Ordens"
        ],
        "summary": "Ordens conferidas ainda em O (operação) ou V (vistoria)",
        "description": "Quando o app exige conferência (parâmetros OPERACAO_CARREGAMENTO_CONFERENCIA, OPERACAO_DESCARREGAMENTO_CONFERENCIA ou OPERACAO_ABASTECIMENTO_CONFERENCIA = S), a ordem só finaliza depois de conferida. POST (ou PUT, que é idêntico) grava data_hora_conferencia = agora numa ordem em O (operação) ou V (vistoria) dentro da validade. GET lista as ordens já conferidas que ainda estão em O ou V.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_conferencia",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "C (carregamento, padrão), D (descarregamento) ou A (abastecimento)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id_ordem": 123456,
                      "tipo": "C",
                      "situacao": "O",
                      "data_hora": "2026-11-12 09:30:00",
                      "id_cliente": 101,
                      "cliente": "CLIENTE EXEMPLO",
                      "id_veiculo": 3001,
                      "veiculo": "ABC1D23",
                      "id_motorista": 2001,
                      "motorista": "MOTORISTA",
                      "produtos": "DIESEL S10",
                      "transferencia": "N"
                    }
                  ],
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Ordens"
        ],
        "summary": "Registra a conferência da ordem",
        "description": "Quando o app exige conferência (parâmetros OPERACAO_CARREGAMENTO_CONFERENCIA, OPERACAO_DESCARREGAMENTO_CONFERENCIA ou OPERACAO_ABASTECIMENTO_CONFERENCIA = S), a ordem só finaliza depois de conferida. POST (ou PUT, que é idêntico) grava data_hora_conferencia = agora numa ordem em O (operação) ou V (vistoria) dentro da validade. GET lista as ordens já conferidas que ainda estão em O ou V.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_conferencia",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "situacao": "ORDEM CONFERIDA",
                  "id_ordem": 123456,
                  "tipo": "C",
                  "id_cliente": 101,
                  "cliente": "CLIENTE EXEMPLO",
                  "id_veiculo": 3001,
                  "veiculo": "ABC1D23",
                  "id_motorista": 2001,
                  "motorista": "MOTORISTA 01",
                  "produtos": "DIESEL S10"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Ordens"
        ],
        "summary": "Igual ao POST",
        "description": "Quando o app exige conferência (parâmetros OPERACAO_CARREGAMENTO_CONFERENCIA, OPERACAO_DESCARREGAMENTO_CONFERENCIA ou OPERACAO_ABASTECIMENTO_CONFERENCIA = S), a ordem só finaliza depois de conferida. POST (ou PUT, que é idêntico) grava data_hora_conferencia = agora numa ordem em O (operação) ou V (vistoria) dentro da validade. GET lista as ordens já conferidas que ainda estão em O ou V.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "put_conferencia",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem. Não aceita o número nem o codigo_interno."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "situacao": "ORDEM CONFERIDA",
                  "id_ordem": 123456,
                  "tipo": "C",
                  "id_cliente": 101,
                  "cliente": "CLIENTE EXEMPLO",
                  "id_veiculo": 3001,
                  "veiculo": "ABC1D23",
                  "id_motorista": 2001,
                  "motorista": "MOTORISTA 01",
                  "produtos": "DIESEL S10"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/notaFiscal": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Consulta nota fiscal por id ou chave",
        "description": "Devolve a identificação e a situação de uma NF-e que já existe no PetroW, localizada por id_nota_fiscal ou pela chave de 44 dígitos. Só leitura. Acesso com perfil cliente ou de filial só vê notas do próprio cliente ou filial.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_notaFiscal",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_nota_fiscal",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da nota fiscal. (Ou chave (44 dígitos da NF-e; aceita com máscara).)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_nota_fiscal": 1001,
                  "chave": "41260100000000000100550010000012341000012345",
                  "numero": 1234,
                  "serie": 1,
                  "situacao": "AUTORIZADA"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/importarNotaFiscal": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Consulta o andamento",
        "description": "O GET não restringe pelo escopo do acesso (cliente ou filial): consulta qualquer pedido do app.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_importarNotaFiscal",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_importar_nota_fiscal",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do pedido de importação (Ou chave (44 dígitos).)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_importar_nota_fiscal": 55,
                  "chave": "41260100000000000100550010000012341000012345",
                  "xml_ok": "S",
                  "id_nota_fiscal": 1001
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Coloca a chave na fila de importação",
        "description": "A chave vai na query string, não no corpo. O corpo é ignorado.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "post_importarNotaFiscal",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "chave",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chave de acesso da NF-e (44 dígitos; aceita máscara)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_importar_nota_fiscal": 55
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/conhecimentoTransporte": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Consulta CT-e por id ou chave",
        "description": "Na busca por chave, só o formato (44 dígitos) é verificado.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_conhecimentoTransporte",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_conhecimento_transporte",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do CT-e (Ou chave (44 dígitos).)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_conhecimento_transporte": 501,
                  "chave": "41260100000000000100570010000004561000045678",
                  "numero": 456,
                  "serie": 1,
                  "situacao": "AUTORIZADA"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/importarConhecimentoTransporte": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Consulta o andamento",
        "description": "O GET não restringe pelo escopo do acesso (cliente ou filial): consulta qualquer pedido do app.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_importarConhecimentoTransporte",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_importar_conhecimento_transporte",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do pedido de importação (Ou chave (44 dígitos).)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_importar_conhecimento_transporte": 55,
                  "chave": "41260100000000000100550010000012341000012345",
                  "xml_ok": "S",
                  "id_conhecimento_transporte": 1001
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Coloca a chave na fila de importação",
        "description": "A chave vai na query string, não no corpo. O corpo é ignorado.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "post_importarConhecimentoTransporte",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "chave",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Chave de acesso do CT-e (44 dígitos; aceita máscara)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_importar_conhecimento_transporte": 55
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/laudoProduto": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Consulta um laudo com checklist, vínculos e PDF",
        "description": "Cria, consulta, altera e desativa laudos de produto. O laudo nasce pendente (aprovado = X). Aprovar ou reprovar não é feito por esta API; depois de aprovado ou reprovado, o laudo não pode mais ser alterado. O checklist é escolhido pela configuração de checklist de laudo mais específica para filial × fornecedor × produto × grade × tipo. O GET lista todas as perguntas desse checklist (respondidas ou não); POST e PUT gravam as respostas por id_checklist_item (criam a resposta ou alteram a existente). Acesso com perfil filial ou rede só acessa laudos da filial; acesso com perfil cliente só consulta laudos ligados a ordens do cliente.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_laudoProduto",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_laudo_produto",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do laudo"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_laudo_produto": 77,
                  "id_tx_estabelecimento": 3,
                  "id_fornecedor": 12,
                  "id_produto": 5,
                  "quantidade": 30000,
                  "unidade": "L",
                  "numero": "LAU-001",
                  "data_amostra": "2026-11-10",
                  "data_laudo": "2026-11-10",
                  "observacao": "",
                  "ativo": true,
                  "tipo": "",
                  "id_produto_grade": 0,
                  "id_tx_pessoa": 0,
                  "data_hora": null,
                  "aprovado": "X",
                  "origem": "",
                  "lacres": "123;124",
                  "checklist": {
                    "descricao": "LAUDO DE RECEBIMENTO",
                    "observacoes": "",
                    "rodape": "",
                    "respostas": [
                      {
                        "id_checklist_item": 48,
                        "pergunta": "ASPECTO",
                        "resposta": "LÍMPIDO",
                        "aprovado": true,
                        "observacao": ""
                      },
                      {
                        "id_checklist_item": 49,
                        "pergunta": "COR",
                        "resposta": "",
                        "aprovado": false,
                        "observacao": ""
                      }
                    ]
                  },
                  "ordem": [
                    {
                      "tipo": "D",
                      "id_ordem": 9001,
                      "produtos": [
                        {
                          "id_produto": 5
                        }
                      ]
                    }
                  ],
                  "estoque": [
                    {
                      "id_estoque": 10,
                      "observacao": ""
                    }
                  ],
                  "pedido": [
                    {
                      "id_pedido": 300,
                      "tipo": "V",
                      "observacao": "",
                      "ativo": true,
                      "itens": [
                        {
                          "descricao": "ETANOL",
                          "id_produto": 5,
                          "ativo": true
                        }
                      ]
                    }
                  ],
                  "conhecimento_transporte": [
                    {
                      "chave": "41260100000000000100570010000004561000045678",
                      "numero": 456,
                      "serie": 1
                    }
                  ],
                  "nota_fiscal": [
                    {
                      "chave": "41260100000000000100550010000012341000012345",
                      "numero": 1234,
                      "serie": 1
                    }
                  ],
                  "batelada": [
                    {
                      "id_batelada": 20,
                      "ativo": true,
                      "produtos": [
                        {
                          "id_produto": 5
                        }
                      ]
                    }
                  ],
                  "contrato_coleta": [
                    {
                      "id_contrato_coleta": 40
                    }
                  ],
                  "pdf_base64": "JVBERi0xLjQK..."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Cria um laudo (e respostas do checklist)",
        "description": "Laudo e respostas são gravados juntos: qualquer erro desfaz tudo. Sem 'checklist' no corpo, nenhuma resposta é gravada.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_laudoProduto",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id_tx_estabelecimento": {
                    "type": "integer",
                    "description": "Filial do laudo. Alternativa: cpf_cnpj_tx_estabelecimento. Sem ela, usa a filial do acesso com perfil filial (0 para os demais tipos)."
                  },
                  "cpf_cnpj_tx_estabelecimento": {
                    "type": "string",
                    "description": "CNPJ da filial (usado se id_tx_estabelecimento não vier)."
                  },
                  "id_fornecedor": {
                    "type": "integer",
                    "description": "Fornecedor. Alternativa: cpf_cnpj_fornecedor."
                  },
                  "cpf_cnpj_fornecedor": {
                    "type": "string",
                    "description": "CNPJ/CPF do fornecedor (usado se id_fornecedor não vier)."
                  },
                  "id_produto": {
                    "type": "integer",
                    "description": "Produto (só o id)."
                  },
                  "id_produto_grade": {
                    "type": "integer",
                    "description": "Grade do produto (padrão 0)"
                  },
                  "quantidade": {
                    "type": "number",
                    "description": "Quantidade (padrão 0)"
                  },
                  "unidade": {
                    "type": "string",
                    "description": "L, M3, KG, TON ou UN (padrão L)"
                  },
                  "numero": {
                    "type": "string",
                    "description": "Número do laudo"
                  },
                  "data_amostra": {
                    "type": "string",
                    "format": "date",
                    "description": "Data da amostra, AAAA-MM-DD. Formato inválido = 400. Sem o campo: no POST, a data de hoje; no PUT, a data atual é mantida."
                  },
                  "data_laudo": {
                    "type": "string",
                    "format": "date",
                    "description": "Data do laudo, AAAA-MM-DD. Mesmas regras de data_amostra."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Tipo do laudo (texto livre; também usado para escolher o checklist)."
                  },
                  "origem": {
                    "type": "string",
                    "description": "Origem"
                  },
                  "lacres": {
                    "type": "string",
                    "description": "Lacres"
                  },
                  "observacao": {
                    "type": "string",
                    "description": "Observação"
                  },
                  "checklist": {
                    "type": "string",
                    "description": "Respostas do checklist: lista de {id_checklist_item, resposta, observacao} ou objeto {\"respostas\":[…]} (o mesmo formato devolvido no GET)."
                  }
                }
              },
              "example": {
                "cpf_cnpj_tx_estabelecimento": "00.000.000/0001-00",
                "cpf_cnpj_fornecedor": "11.111.111/0001-11",
                "id_produto": 5,
                "quantidade": 30000,
                "unidade": "L",
                "numero": "LAU-001",
                "data_amostra": "2026-11-10",
                "data_laudo": "2026-11-10",
                "lacres": "123;124",
                "checklist": [
                  {
                    "id_checklist_item": 48,
                    "resposta": "LÍMPIDO",
                    "observacao": ""
                  },
                  {
                    "id_checklist_item": 49,
                    "resposta": "INCOLOR"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_laudo_produto": 77
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Altera um laudo pendente (e respostas)",
        "description": "Atenção: o PUT não é parcial. Todos os campos do laudo são regravados com o valor do corpo ou com o padrão (0, '', 'L'): mande o laudo completo. data_amostra e data_laudo só mudam quando enviadas. As respostas do checklist só mudam para os itens enviados.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "put_laudoProduto",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_laudo_produto",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do laudo"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "id_tx_estabelecimento": {
                    "type": "integer",
                    "description": "Filial do laudo. Alternativa: cpf_cnpj_tx_estabelecimento. Sem ela, usa a filial do acesso com perfil filial (0 para os demais tipos)."
                  },
                  "cpf_cnpj_tx_estabelecimento": {
                    "type": "string",
                    "description": "CNPJ da filial (usado se id_tx_estabelecimento não vier)."
                  },
                  "id_fornecedor": {
                    "type": "integer",
                    "description": "Fornecedor. Alternativa: cpf_cnpj_fornecedor."
                  },
                  "cpf_cnpj_fornecedor": {
                    "type": "string",
                    "description": "CNPJ/CPF do fornecedor (usado se id_fornecedor não vier)."
                  },
                  "id_produto": {
                    "type": "integer",
                    "description": "Produto (só o id)."
                  },
                  "id_produto_grade": {
                    "type": "integer",
                    "description": "Grade do produto (padrão 0)"
                  },
                  "quantidade": {
                    "type": "number",
                    "description": "Quantidade (padrão 0)"
                  },
                  "unidade": {
                    "type": "string",
                    "description": "L, M3, KG, TON ou UN (padrão L)"
                  },
                  "numero": {
                    "type": "string",
                    "description": "Número do laudo"
                  },
                  "data_amostra": {
                    "type": "string",
                    "format": "date",
                    "description": "Data da amostra, AAAA-MM-DD. Formato inválido = 400. Sem o campo: no POST, a data de hoje; no PUT, a data atual é mantida."
                  },
                  "data_laudo": {
                    "type": "string",
                    "format": "date",
                    "description": "Data do laudo, AAAA-MM-DD. Mesmas regras de data_amostra."
                  },
                  "tipo": {
                    "type": "string",
                    "description": "Tipo do laudo (texto livre; também usado para escolher o checklist)."
                  },
                  "origem": {
                    "type": "string",
                    "description": "Origem"
                  },
                  "lacres": {
                    "type": "string",
                    "description": "Lacres"
                  },
                  "observacao": {
                    "type": "string",
                    "description": "Observação"
                  },
                  "checklist": {
                    "type": "string",
                    "description": "Respostas do checklist: lista de {id_checklist_item, resposta, observacao} ou objeto {\"respostas\":[…]} (o mesmo formato devolvido no GET)."
                  }
                }
              },
              "example": {
                "id_tx_estabelecimento": 3,
                "id_fornecedor": 12,
                "id_produto": 5,
                "quantidade": 30000,
                "unidade": "L",
                "numero": "LAU-001",
                "data_amostra": "2026-11-10",
                "data_laudo": "2026-11-10",
                "checklist": {
                  "respostas": [
                    {
                      "id_checklist_item": 49,
                      "resposta": "INCOLOR",
                      "observacao": "conferido"
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Desativa um laudo",
        "description": "Desativa (ativo = N); não apaga.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_laudoProduto",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_laudo_produto",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do laudo"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/movimentoSaldoDia": {
      "get": {
        "tags": [
          "Notas fiscais, CT-e e laudos"
        ],
        "summary": "Lista o movimento e o saldo por dia",
        "description": "Ordenado por cliente, produto e dia. Sem linhas: data = [] e param só com _size e _page.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_movimentoSaldoDia",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "data_inicial",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Primeiro dia (AAAA-MM-DD). Padrão: 1980-01-01. (Ou data_inicio ou data_ini.)"
          },
          {
            "name": "data_final",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Último dia (AAAA-MM-DD). Padrão: 2099-12-31. (Ou data_fim.)"
          },
          {
            "name": "id_tx_estabelecimento",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Filtra a filial (0 = todas)"
          },
          {
            "name": "id_cliente",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Filtra o cliente (0 = todos)"
          },
          {
            "name": "id_produto",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Filtra o produto (0 = todos) (Ou id_comb.)"
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Página (padrão 1)."
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Itens por página, de 1 a 50 (padrão 50)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_cliente": 10,
                      "cliente": "DISTRIBUIDORA A",
                      "id_produto": 5,
                      "produto": "ETANOL",
                      "dia": "2026-11-10",
                      "saldo_ant_fisico": 100000.0,
                      "saldo_ant_fiscal": 100500.0,
                      "saldo_ant_dif": 500.0,
                      "entrada_fisico": 30000.0,
                      "entrada_fiscal": 30000.0,
                      "entrada_dif": 0.0,
                      "saida_fisico": 20000.0,
                      "saida_fiscal": 20100.0,
                      "saida_dif": 100.0,
                      "saldo_fisico": 110000.0,
                      "saldo_fiscal": 110400.0,
                      "saldo_dif": 400.0
                    }
                  ],
                  "param": {
                    "_count": 1,
                    "_pages": 1,
                    "_size": 50,
                    "_page": 1
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/cliente": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um cliente",
        "description": "Cadastro de cliente (dados da pessoa + cadastro de cliente). Localiza o cliente por id_cliente ou, se id_cliente não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). Acesso com perfil cliente não pode criar (403) e só consulta e altera o próprio cliente.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_cliente",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_cliente",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do cliente (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_cliente": 123,
                  "codigo_erp": "C001",
                  "simp_instalacao": "1234567",
                  "simp_agente": "1234567890",
                  "id_tx_pessoa": 321,
                  "cpf_cnpj": "00000000000100",
                  "rg_inscricao": "ISENTO",
                  "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                  "identificacao": "EXEMPLO",
                  "nascimento_fundacao": "2010-01-01",
                  "telefone": "4133334444",
                  "celular": "41999990000",
                  "email": "contato@exemplo.com.br",
                  "cep": "80000000",
                  "logradouro": "RUA EXEMPLO",
                  "numero": 100,
                  "complemento": "",
                  "bairro": "CENTRO",
                  "localidade": "CURITIBA",
                  "estado": "PR",
                  "crt": "3",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "inscricao_municipal": "",
                  "pais": "BRASIL",
                  "suframa": "",
                  "tipo": "J",
                  "indiedest": "1",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria um cliente",
        "description": "Sempre cria um novo cliente; não altera um existente. Se já houver uma pessoa com o cpf_cnpj, ela é reaproveitada. Se algo falhar, nada é gravado.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "post_cliente",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "simp_instalacao": {
                    "type": "string",
                    "description": "Código SIMP/ANP da instalação (padrão '0000000' na criação)."
                  },
                  "simp_agente": {
                    "type": "string",
                    "description": "Código SIMP/ANP do agente (padrão '0000000000' na criação)."
                  }
                },
                "required": [
                  "cpf_cnpj"
                ]
              },
              "example": {
                "cpf_cnpj": "00.000.000/0001-00",
                "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                "identificacao": "EXEMPLO",
                "email": "contato@exemplo.com.br",
                "cep": "80000-000",
                "logradouro": "RUA EXEMPLO",
                "numero": 100,
                "bairro": "CENTRO",
                "localidade": "CURITIBA",
                "estado": "PR",
                "codigo_erp": "C001",
                "simp_instalacao": "1234567",
                "simp_agente": "1234567890"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_cliente": 123
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera um cliente",
        "description": "Cadastro de cliente (dados da pessoa + cadastro de cliente). Localiza o cliente por id_cliente ou, se id_cliente não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). Acesso com perfil cliente não pode criar (403) e só consulta e altera o próprio cliente.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "put_cliente",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_cliente",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do cliente (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "simp_instalacao": {
                    "type": "string",
                    "description": "Código SIMP/ANP da instalação (padrão '0000000' na criação)."
                  },
                  "simp_agente": {
                    "type": "string",
                    "description": "Código SIMP/ANP do agente (padrão '0000000000' na criação)."
                  }
                }
              },
              "example": {
                "email": "novo@exemplo.com.br",
                "telefone": "4133335555"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa um cliente",
        "description": "Cadastro de cliente (dados da pessoa + cadastro de cliente). Localiza o cliente por id_cliente ou, se id_cliente não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). Acesso com perfil cliente não pode criar (403) e só consulta e altera o próprio cliente.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_cliente",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_cliente",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do cliente (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/fornecedor": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um fornecedor",
        "description": "Cadastro de fornecedor (dados da pessoa + cadastro de fornecedor). Localiza o fornecedor por id_fornecedor ou, se id_fornecedor não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_fornecedor",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_fornecedor",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do fornecedor (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_fornecedor": 123,
                  "codigo_erp": "F001",
                  "id_tx_pessoa": 321,
                  "cpf_cnpj": "00000000000100",
                  "rg_inscricao": "ISENTO",
                  "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                  "identificacao": "EXEMPLO",
                  "nascimento_fundacao": "2010-01-01",
                  "telefone": "4133334444",
                  "celular": "41999990000",
                  "email": "contato@exemplo.com.br",
                  "cep": "80000000",
                  "logradouro": "RUA EXEMPLO",
                  "numero": 100,
                  "complemento": "",
                  "bairro": "CENTRO",
                  "localidade": "CURITIBA",
                  "estado": "PR",
                  "crt": "3",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "inscricao_municipal": "",
                  "pais": "BRASIL",
                  "suframa": "",
                  "tipo": "J",
                  "indiedest": "1",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria um fornecedor",
        "description": "Sempre cria um novo fornecedor; não altera um existente. Se já houver uma pessoa com o cpf_cnpj, ela é reaproveitada. Se algo falhar, nada é gravado.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_fornecedor",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  }
                },
                "required": [
                  "cpf_cnpj"
                ]
              },
              "example": {
                "cpf_cnpj": "00.000.000/0001-00",
                "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                "identificacao": "EXEMPLO",
                "email": "contato@exemplo.com.br",
                "cep": "80000-000",
                "logradouro": "RUA EXEMPLO",
                "numero": 100,
                "bairro": "CENTRO",
                "localidade": "CURITIBA",
                "estado": "PR",
                "codigo_erp": "C001"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_fornecedor": 123
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera um fornecedor",
        "description": "Cadastro de fornecedor (dados da pessoa + cadastro de fornecedor). Localiza o fornecedor por id_fornecedor ou, se id_fornecedor não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_fornecedor",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_fornecedor",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do fornecedor (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  }
                }
              },
              "example": {
                "email": "novo@exemplo.com.br",
                "telefone": "4133335555"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa um fornecedor",
        "description": "Cadastro de fornecedor (dados da pessoa + cadastro de fornecedor). Localiza o fornecedor por id_fornecedor ou, se id_fornecedor não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_fornecedor",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_fornecedor",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do fornecedor (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/transportadora": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta uma transportadora",
        "description": "Cadastro de transportadora (dados da pessoa + cadastro de transportadora). Localiza a transportadora por id_transportadora ou, se id_transportadora não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_transportadora",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_transportadora",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da transportadora. (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_transportadora": 123,
                  "codigo_erp": "T001",
                  "antt": "12345678",
                  "id_tx_pessoa": 321,
                  "cpf_cnpj": "00000000000100",
                  "rg_inscricao": "ISENTO",
                  "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                  "identificacao": "EXEMPLO",
                  "nascimento_fundacao": "2010-01-01",
                  "telefone": "4133334444",
                  "celular": "41999990000",
                  "email": "contato@exemplo.com.br",
                  "cep": "80000000",
                  "logradouro": "RUA EXEMPLO",
                  "numero": 100,
                  "complemento": "",
                  "bairro": "CENTRO",
                  "localidade": "CURITIBA",
                  "estado": "PR",
                  "crt": "3",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "inscricao_municipal": "",
                  "pais": "BRASIL",
                  "suframa": "",
                  "tipo": "J",
                  "indiedest": "1",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria uma transportadora",
        "description": "Sempre cria uma nova transportadora; não altera uma existente. Se já houver uma pessoa com o cpf_cnpj, ela é reaproveitada. Se algo falhar, nada é gravado.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_transportadora",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "antt": {
                    "type": "string",
                    "description": "Registro ANTT (RNTRC)"
                  }
                },
                "required": [
                  "cpf_cnpj"
                ]
              },
              "example": {
                "cpf_cnpj": "00.000.000/0001-00",
                "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                "identificacao": "EXEMPLO",
                "email": "contato@exemplo.com.br",
                "cep": "80000-000",
                "logradouro": "RUA EXEMPLO",
                "numero": 100,
                "bairro": "CENTRO",
                "localidade": "CURITIBA",
                "estado": "PR",
                "codigo_erp": "C001",
                "antt": "12345678"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_transportadora": 123
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera uma transportadora",
        "description": "Cadastro de transportadora (dados da pessoa + cadastro de transportadora). Localiza a transportadora por id_transportadora ou, se id_transportadora não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_transportadora",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_transportadora",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da transportadora. (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf_cnpj": {
                    "type": "string",
                    "description": "CPF ou CNPJ (com ou sem máscara). No POST, se já existir uma pessoa com esse documento no app, ela é reaproveitada e atualizada com os campos enviados."
                  },
                  "rg_inscricao": {
                    "type": "string",
                    "description": "RG ou inscrição estadual"
                  },
                  "nome_razao_social": {
                    "type": "string",
                    "description": "Nome ou razão social"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido / nome fantasia"
                  },
                  "nascimento_fundacao": {
                    "type": "string",
                    "description": "Data de nascimento ou fundação (AAAA-MM-DD)."
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número do endereço (inteiro)"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF (2 letras)"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI do telefone"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI do celular"
                  },
                  "inscricao_municipal": {
                    "type": "string",
                    "description": "Inscrição municipal"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "suframa": {
                    "type": "string",
                    "description": "Inscrição SUFRAMA"
                  },
                  "indiedest": {
                    "type": "string",
                    "description": "Indicador de IE do destinatário (NF-e: 1, 2 ou 9)"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "antt": {
                    "type": "string",
                    "description": "Registro ANTT (RNTRC)"
                  }
                }
              },
              "example": {
                "email": "novo@exemplo.com.br",
                "telefone": "4133335555"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa uma transportadora",
        "description": "Cadastro de transportadora (dados da pessoa + cadastro de transportadora). Localiza a transportadora por id_transportadora ou, se id_transportadora não vier, por cpf_cnpj. Gravação parcial: só os campos presentes no JSON são alterados. Campos de texto precisam vir como texto JSON (entre aspas). DELETE apenas desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_transportadora",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_transportadora",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da transportadora. (Ou cpf_cnpj (CPF/CNPJ com ou sem máscara) na query.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/veiculo": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um veículo",
        "description": "'compartimentos' só aparece se o veículo tiver compartimentos; cada compartimento lista só os níveis com cap_l > 0.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_veiculo",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_veiculo",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do veículo (Ou placa.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_veiculo": 800,
                  "tipo": "CARRETA",
                  "placa": "ABC1D23",
                  "renavam": "00000000000",
                  "ano_fabricacao": "2020",
                  "ano_modelo": "2021",
                  "pais": "BRASIL",
                  "estado": "PR",
                  "localidade": "CURITIBA",
                  "capacidade_litros": 45000,
                  "compartimentos": [
                    {
                      "compartimento": 1,
                      "lacres": 2,
                      "niveis": [
                        {
                          "nivel": 1,
                          "cap_l": 15000,
                          "ev_mm": 120,
                          "ec_mm": 300,
                          "et_mm": 1500
                        }
                      ]
                    }
                  ],
                  "licencas_ambientais": [
                    {
                      "estado": "PR",
                      "validade": "2027-06-30"
                    }
                  ],
                  "validade_certificado": "2027-01-01",
                  "validade_vistoria": "2027-05-10",
                  "validade_civ": "2027-01-01",
                  "validade_cipp": "2027-01-01",
                  "validade_cert_ibama": "2027-01-01",
                  "validade_aut_ibama": "2027-01-01",
                  "validade_tacografo": "2027-01-01",
                  "cor": "BRANCA",
                  "vistoria_carregamento": "N",
                  "vistoria_descarregamento": "N",
                  "codigo_erp": "V001",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria um veículo",
        "description": "Cadastro de veículos e carretas. Localiza o veículo por id_veiculo ou, se id_veiculo não vier, por placa. POST sempre cria (placa ou RENAVAM já cadastrados dão 'Dados já cadastrados'). PUT é parcial (só os campos enviados). DELETE desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_veiculo",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "placa": {
                    "type": "string",
                    "description": "Placa (ex.: ABC1D23)"
                  },
                  "tipo": {
                    "type": "string",
                    "description": "CAVALO, CARRETA, TRUCK, ESPECIAL ou OUTRO."
                  },
                  "renavam": {
                    "type": "string",
                    "description": "RENAVAM"
                  },
                  "ano_fabricacao": {
                    "type": "string",
                    "description": "Ano de fabricação (texto)."
                  },
                  "ano_modelo": {
                    "type": "string",
                    "description": "Ano do modelo (texto)."
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "capacidade_litros": {
                    "type": "integer",
                    "description": "Capacidade total em litros"
                  },
                  "quant_compartimentos": {
                    "type": "integer",
                    "description": "Quantidade de compartimentos (recalculada a partir de 'compartimentos' quando esse campo vier)."
                  },
                  "validade_certificado": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_vistoria": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_civ": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_cipp": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_cert_ibama": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_aut_ibama": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_tacografo": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "cor": {
                    "type": "string",
                    "description": "Cor"
                  },
                  "vistoria_carregamento": {
                    "type": "string",
                    "description": "S ou N: exige vistoria no carregamento."
                  },
                  "vistoria_descarregamento": {
                    "type": "string",
                    "description": "S ou N: exige vistoria no descarregamento."
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "compartimentos": {
                    "type": "array",
                    "items": {},
                    "description": "[{compartimento (1–15; padrão: posição na lista + 1), lacres (inteiro), niveis:[{nivel (1–10; padrão: posição na lista + 1), cap_l, ev_mm, ec_mm, et_mm (só nível 1)}]}]. Nível 1 com cap_l = 0 apaga o compartimento e renumera os demais (capacidade e quantidade de compartimentos são recalculadas)."
                  },
                  "licencas_ambientais": {
                    "type": "array",
                    "items": {},
                    "description": "[{estado (UF), validade (AAAA-MM-DD)}]: marca a licença ambiental como ativa na UF. Não é possível desmarcar por esta API."
                  }
                },
                "required": [
                  "placa"
                ]
              },
              "example": {
                "placa": "ABC1D23",
                "tipo": "CARRETA",
                "renavam": "00000000000",
                "ano_fabricacao": "2020",
                "ano_modelo": "2021",
                "estado": "PR",
                "localidade": "CURITIBA",
                "compartimentos": [
                  {
                    "compartimento": 1,
                    "lacres": 2,
                    "niveis": [
                      {
                        "nivel": 1,
                        "cap_l": 15000,
                        "ev_mm": 120,
                        "ec_mm": 300,
                        "et_mm": 1500
                      }
                    ]
                  },
                  {
                    "compartimento": 2,
                    "lacres": 2,
                    "niveis": [
                      {
                        "nivel": 1,
                        "cap_l": 30000
                      }
                    ]
                  }
                ],
                "licencas_ambientais": [
                  {
                    "estado": "PR",
                    "validade": "2027-06-30"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_veiculo": 800
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera um veículo (parcial)",
        "description": "Cadastro de veículos e carretas. Localiza o veículo por id_veiculo ou, se id_veiculo não vier, por placa. POST sempre cria (placa ou RENAVAM já cadastrados dão 'Dados já cadastrados'). PUT é parcial (só os campos enviados). DELETE desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_veiculo",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_veiculo",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do veículo (Ou placa.)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "placa": {
                    "type": "string",
                    "description": "Placa (ex.: ABC1D23)"
                  },
                  "tipo": {
                    "type": "string",
                    "description": "CAVALO, CARRETA, TRUCK, ESPECIAL ou OUTRO."
                  },
                  "renavam": {
                    "type": "string",
                    "description": "RENAVAM"
                  },
                  "ano_fabricacao": {
                    "type": "string",
                    "description": "Ano de fabricação (texto)."
                  },
                  "ano_modelo": {
                    "type": "string",
                    "description": "Ano do modelo (texto)."
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "capacidade_litros": {
                    "type": "integer",
                    "description": "Capacidade total em litros"
                  },
                  "quant_compartimentos": {
                    "type": "integer",
                    "description": "Quantidade de compartimentos (recalculada a partir de 'compartimentos' quando esse campo vier)."
                  },
                  "validade_certificado": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_vistoria": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_civ": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_cipp": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_cert_ibama": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_aut_ibama": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_tacografo": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "cor": {
                    "type": "string",
                    "description": "Cor"
                  },
                  "vistoria_carregamento": {
                    "type": "string",
                    "description": "S ou N: exige vistoria no carregamento."
                  },
                  "vistoria_descarregamento": {
                    "type": "string",
                    "description": "S ou N: exige vistoria no descarregamento."
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  },
                  "compartimentos": {
                    "type": "array",
                    "items": {},
                    "description": "[{compartimento (1–15; padrão: posição na lista + 1), lacres (inteiro), niveis:[{nivel (1–10; padrão: posição na lista + 1), cap_l, ev_mm, ec_mm, et_mm (só nível 1)}]}]. Nível 1 com cap_l = 0 apaga o compartimento e renumera os demais (capacidade e quantidade de compartimentos são recalculadas)."
                  },
                  "licencas_ambientais": {
                    "type": "array",
                    "items": {},
                    "description": "[{estado (UF), validade (AAAA-MM-DD)}]: marca a licença ambiental como ativa na UF. Não é possível desmarcar por esta API."
                  }
                }
              },
              "example": {
                "validade_vistoria": "2027-05-10",
                "compartimentos": [
                  {
                    "compartimento": 2,
                    "niveis": [
                      {
                        "nivel": 1,
                        "cap_l": 0
                      }
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa um veículo",
        "description": "Cadastro de veículos e carretas. Localiza o veículo por id_veiculo ou, se id_veiculo não vier, por placa. POST sempre cria (placa ou RENAVAM já cadastrados dão 'Dados já cadastrados'). PUT é parcial (só os campos enviados). DELETE desativa (ativo = N). O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_veiculo",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_veiculo",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do veículo (Ou placa.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/motorista": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um motorista",
        "description": "Cadastro de motoristas (dados da pessoa, CNH e validades de cursos). Localiza o motorista por id_motorista ou, se id_motorista não vier, por cpf. POST sempre cria um motorista: a pessoa com o mesmo CPF é reaproveitada; se ela já é motorista, responde 'Dados já cadastrados'. PUT é parcial. DELETE desativa (ativo = N). validade_integracao também é renovada quando um checklist do motorista é aprovado. O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_motorista",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_motorista",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do motorista (Ou cpf.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_motorista": 600,
                  "numero_cnh": "00000000000",
                  "registro_cnh": "",
                  "estado_cnh": "PR",
                  "localidade_cnh": "CURITIBA",
                  "emissao_cnh": "2023-03-01",
                  "primeira_cnh": "2010-01-01",
                  "categoria_cnh": "E",
                  "validade_cnh": "2028-03-01",
                  "observacoes_cnh": "",
                  "validade_nr_35": "2027-01-01",
                  "validade_nr_20": "2027-01-01",
                  "validade_mopp": "2027-08-01",
                  "validade_integracao": "2027-05-10",
                  "validade_toxicologico": "2027-01-01",
                  "pais_cnh": "BRASIL",
                  "vistoria_carregamento": "N",
                  "vistoria_descarregamento": "N",
                  "codigo_erp": "M001",
                  "id_tx_pessoa": 321,
                  "cpf": "00000000191",
                  "rg": "",
                  "nome": "MOTORISTA EXEMPLO",
                  "identificacao": "",
                  "nascimento": "1980-01-01",
                  "telefone": "",
                  "celular": "41999990000",
                  "email": "",
                  "cep": "",
                  "logradouro": "",
                  "numero": 0,
                  "complemento": "",
                  "bairro": "",
                  "localidade": "",
                  "estado": "PR",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "pais": "BRASIL",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria um motorista",
        "description": "Cadastro de motoristas (dados da pessoa, CNH e validades de cursos). Localiza o motorista por id_motorista ou, se id_motorista não vier, por cpf. POST sempre cria um motorista: a pessoa com o mesmo CPF é reaproveitada; se ela já é motorista, responde 'Dados já cadastrados'. PUT é parcial. DELETE desativa (ativo = N). validade_integracao também é renovada quando um checklist do motorista é aprovado. O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_motorista",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf": {
                    "type": "string",
                    "description": "CPF (com ou sem máscara). No POST, a pessoa que já tem esse CPF é reaproveitada e atualizada."
                  },
                  "rg": {
                    "type": "string",
                    "description": "RG"
                  },
                  "nome": {
                    "type": "string",
                    "description": "Nome"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido"
                  },
                  "nascimento": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "numero_cnh": {
                    "type": "string",
                    "description": "Número da CNH"
                  },
                  "registro_cnh": {
                    "type": "string",
                    "description": "Registro da CNH"
                  },
                  "estado_cnh": {
                    "type": "string",
                    "description": "UF da CNH"
                  },
                  "localidade_cnh": {
                    "type": "string",
                    "description": "Município da CNH"
                  },
                  "emissao_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "primeira_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "categoria_cnh": {
                    "type": "string",
                    "description": "Categoria (ex.: E)"
                  },
                  "validade_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "observacoes_cnh": {
                    "type": "string",
                    "description": "Observações"
                  },
                  "validade_nr_35": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_nr_20": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_mopp": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_integracao": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_toxicologico": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "pais_cnh": {
                    "type": "string",
                    "description": "País da CNH"
                  },
                  "vistoria_carregamento": {
                    "type": "string",
                    "description": "S/N"
                  },
                  "vistoria_descarregamento": {
                    "type": "string",
                    "description": "S/N"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  }
                },
                "required": [
                  "cpf"
                ]
              },
              "example": {
                "cpf": "000.000.001-91",
                "nome": "MOTORISTA EXEMPLO",
                "celular": "41999990000",
                "numero_cnh": "00000000000",
                "categoria_cnh": "E",
                "validade_cnh": "2028-03-01",
                "validade_mopp": "2027-08-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_motorista": 600
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera um motorista (parcial)",
        "description": "Cadastro de motoristas (dados da pessoa, CNH e validades de cursos). Localiza o motorista por id_motorista ou, se id_motorista não vier, por cpf. POST sempre cria um motorista: a pessoa com o mesmo CPF é reaproveitada; se ela já é motorista, responde 'Dados já cadastrados'. PUT é parcial. DELETE desativa (ativo = N). validade_integracao também é renovada quando um checklist do motorista é aprovado. O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_motorista",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_motorista",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do motorista (Ou cpf.)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cpf": {
                    "type": "string",
                    "description": "CPF (com ou sem máscara). No POST, a pessoa que já tem esse CPF é reaproveitada e atualizada."
                  },
                  "rg": {
                    "type": "string",
                    "description": "RG"
                  },
                  "nome": {
                    "type": "string",
                    "description": "Nome"
                  },
                  "identificacao": {
                    "type": "string",
                    "description": "Apelido"
                  },
                  "nascimento": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "telefone": {
                    "type": "string",
                    "description": "Telefone"
                  },
                  "celular": {
                    "type": "string",
                    "description": "Celular"
                  },
                  "email": {
                    "type": "string",
                    "description": "E-mail"
                  },
                  "cep": {
                    "type": "string",
                    "description": "CEP"
                  },
                  "logradouro": {
                    "type": "string",
                    "description": "Logradouro"
                  },
                  "numero": {
                    "type": "integer",
                    "description": "Número"
                  },
                  "complemento": {
                    "type": "string",
                    "description": "Complemento"
                  },
                  "bairro": {
                    "type": "string",
                    "description": "Bairro"
                  },
                  "localidade": {
                    "type": "string",
                    "description": "Município"
                  },
                  "estado": {
                    "type": "string",
                    "description": "UF"
                  },
                  "ddi_telefone": {
                    "type": "integer",
                    "description": "DDI"
                  },
                  "ddi_celular": {
                    "type": "integer",
                    "description": "DDI"
                  },
                  "pais": {
                    "type": "string",
                    "description": "País"
                  },
                  "numero_cnh": {
                    "type": "string",
                    "description": "Número da CNH"
                  },
                  "registro_cnh": {
                    "type": "string",
                    "description": "Registro da CNH"
                  },
                  "estado_cnh": {
                    "type": "string",
                    "description": "UF da CNH"
                  },
                  "localidade_cnh": {
                    "type": "string",
                    "description": "Município da CNH"
                  },
                  "emissao_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "primeira_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "categoria_cnh": {
                    "type": "string",
                    "description": "Categoria (ex.: E)"
                  },
                  "validade_cnh": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "observacoes_cnh": {
                    "type": "string",
                    "description": "Observações"
                  },
                  "validade_nr_35": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_nr_20": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_mopp": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_integracao": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "validade_toxicologico": {
                    "type": "string",
                    "format": "date",
                    "description": "AAAA-MM-DD"
                  },
                  "pais_cnh": {
                    "type": "string",
                    "description": "País da CNH"
                  },
                  "vistoria_carregamento": {
                    "type": "string",
                    "description": "S/N"
                  },
                  "vistoria_descarregamento": {
                    "type": "string",
                    "description": "S/N"
                  },
                  "codigo_erp": {
                    "type": "string",
                    "description": "Código no ERP"
                  }
                }
              },
              "example": {
                "validade_mopp": "2028-08-01"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa um motorista",
        "description": "Cadastro de motoristas (dados da pessoa, CNH e validades de cursos). Localiza o motorista por id_motorista ou, se id_motorista não vier, por cpf. POST sempre cria um motorista: a pessoa com o mesmo CPF é reaproveitada; se ela já é motorista, responde 'Dados já cadastrados'. PUT é parcial. DELETE desativa (ativo = N). validade_integracao também é renovada quando um checklist do motorista é aprovado. O endpoint não restringe pelo escopo do acesso (cliente ou filial): vale só a permissão de acesso ao endpoint.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "delete_motorista",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_motorista",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do motorista (Ou cpf.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/produto": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um produto",
        "description": "Atenção: alguns campos têm grafia diferente da esperada e devem ser lidos exatamente assim: 'undiade', 'id_produto_composicacaoN' e 'perc_composicacaoN'.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_produto",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_produto",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do produto"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_produto": 5,
                  "grupo": "ETANOL",
                  "nome": "ETANOL HIDRATADO",
                  "apelido": "EHC",
                  "simp": "810102001",
                  "densidade_a_20": 0.8093,
                  "densidade_a_20_min": 0.8076,
                  "densidade_a_20_max": 0.811,
                  "ordem_carregamento": "S",
                  "ordem_descarregamento": "S",
                  "inpm_min": 92.5,
                  "inpm_max": 95.4,
                  "tipo": "C",
                  "controla_quantidade": "S",
                  "controla_temp_dens": "S",
                  "pode_transferencia": "S",
                  "codigo_erp": "P005",
                  "gerar_simp": "S",
                  "aditivado": "N",
                  "apelido_padrao": "EHC",
                  "id_cliente": 0,
                  "pode_venda": "S",
                  "marcador": "N",
                  "cod_aditivo": "",
                  "perc_aditivo": 0,
                  "cod_marcador": "",
                  "perc_marcador": 0,
                  "classificacao": "",
                  "undiade": "L",
                  "para_litro": 1,
                  "para_kg": 0.8093,
                  "grade": "N",
                  "pedido": "S",
                  "contrato": "S",
                  "lastro": "N",
                  "extipi": "",
                  "cest": "",
                  "genero": "",
                  "id_produto_composicacao1": 0,
                  "perc_composicacao1": 0,
                  "id_produto_composicacao2": 0,
                  "perc_composicacao2": 0,
                  "id_produto_composicacao3": 0,
                  "perc_composicacao3": 0,
                  "id_produto_composicacao4": 0,
                  "perc_composicacao4": 0,
                  "id_produto_composicacao5": 0,
                  "perc_composicacao5": 0,
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/txPessoa": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta uma pessoa",
        "description": "Devolve os dados cadastrais de uma pessoa (física ou jurídica) do app, por id_tx_pessoa ou CPF/CNPJ. Pessoa ligada a um cliente só é vista por quem tem acesso a esse cliente.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_txPessoa",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_pessoa",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da pessoa (Ou cpf_cnpj.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_tx_pessoa": 321,
                  "cpf_cnpj": "00000000000100",
                  "rg_inscricao": "ISENTO",
                  "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                  "identificacao": "EXEMPLO",
                  "nascimento_fundacao": "2010-01-01",
                  "telefone": "4133334444",
                  "celular": "41999990000",
                  "email": "contato@exemplo.com.br",
                  "cep": "80000000",
                  "logradouro": "RUA EXEMPLO",
                  "numero": 100,
                  "complemento": "",
                  "bairro": "CENTRO",
                  "localidade": "CURITIBA",
                  "estado": "PR",
                  "crt": "3",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "inscricao_municipal": "",
                  "pais": "BRASIL",
                  "suframa": "",
                  "tipo": "J",
                  "indiedest": "1",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/txEstabelecimento": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta uma filial",
        "description": "Para acesso com perfil filial, o id_tx_estabelecimento da query é substituído pelo da própria filial (só vê a própria).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_txEstabelecimento",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_estabelecimento",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da filial (Ou cpf_cnpj.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_tx_estabelecimento": 3,
                  "nome": "FILIAL EXEMPLO",
                  "id_tx_pessoa": 321,
                  "cpf_cnpj": "00000000000100",
                  "rg_inscricao": "ISENTO",
                  "nome_razao_social": "EMPRESA EXEMPLO LTDA",
                  "identificacao": "EXEMPLO",
                  "nascimento_fundacao": "2010-01-01",
                  "telefone": "4133334444",
                  "celular": "41999990000",
                  "email": "contato@exemplo.com.br",
                  "cep": "80000000",
                  "logradouro": "RUA EXEMPLO",
                  "numero": 100,
                  "complemento": "",
                  "bairro": "CENTRO",
                  "localidade": "CURITIBA",
                  "estado": "PR",
                  "crt": "3",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "inscricao_municipal": "",
                  "pais": "BRASIL",
                  "suframa": "",
                  "tipo": "J",
                  "indiedest": "1",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/operador": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta um operador",
        "description": "Devolve o operador (funcionário que opera o carregamento e o descarregamento) e os dados da pessoa, por id_operador ou CPF. Só leitura. Não restringe pelo escopo do acesso.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_operador",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_operador",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id do operador (Ou cpf.)"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_operador": 40,
                  "validade_nr_35": "2027-01-01",
                  "validade_nr_20": "2027-01-01",
                  "validade_mopp": "2027-01-01",
                  "validade_integracao": "2027-01-01",
                  "pode_completar": "N",
                  "limite_completar": 0,
                  "codigo_erp": "O040",
                  "id_tx_pessoa": 330,
                  "cpf": "00000000191",
                  "rg": "",
                  "nome": "OPERADOR EXEMPLO",
                  "identificacao": "",
                  "nascimento": "1985-01-01",
                  "telefone": "",
                  "celular": "",
                  "email": "",
                  "cep": "",
                  "logradouro": "",
                  "numero": 0,
                  "complemento": "",
                  "bairro": "",
                  "localidade": "",
                  "estado": "PR",
                  "ddi_telefone": 55,
                  "ddi_celular": 55,
                  "pais": "BRASIL",
                  "ativo": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/txObservacao": {
      "get": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Consulta uma observação ou as de um registro",
        "description": "Por id_tx_observacao a resposta é um objeto plano (sem data[]): {status, id_tx_observacao, tabela, id, observacao, data_hora, ativo}.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_txObservacao",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_observacao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Id da observação (tem prioridade)."
          },
          {
            "name": "tabela",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Tabela (usar junto com id quando não houver id_tx_observacao)."
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Id do registro na tabela."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_tx_observacao": 15,
                      "observacao": "Cliente pediu conferência",
                      "data_hora": "2026-11-10 09:30:00",
                      "ativo": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Cria uma observação",
        "description": "Grava e consulta observações (texto) ligadas a qualquer registro do sistema, identificado por tabela + id. GET por id_tx_observacao devolve uma; por tabela + id devolve a lista. DELETE desativa (ativo = N). A API não verifica se a tabela e o id existem e não restringe pelo escopo do acesso (só pelo app).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "post_txObservacao",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tabela": {
                    "type": "string",
                    "description": "Nome da tabela do sistema a que a observação se refere (ex.: ordem)."
                  },
                  "id": {
                    "type": "integer",
                    "description": "Id do registro nessa tabela."
                  },
                  "observacao": {
                    "type": "string",
                    "description": "Texto"
                  },
                  "ativo": {
                    "type": "boolean",
                    "description": "true/false"
                  }
                },
                "required": [
                  "tabela",
                  "id",
                  "observacao"
                ]
              },
              "example": {
                "tabela": "ordem",
                "id": 9001,
                "observacao": "Cliente pediu conferência"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_tx_observacao": 15
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Altera uma observação (parcial)",
        "description": "Grava e consulta observações (texto) ligadas a qualquer registro do sistema, identificado por tabela + id. GET por id_tx_observacao devolve uma; por tabela + id devolve a lista. DELETE desativa (ativo = N). A API não verifica se a tabela e o id existem e não restringe pelo escopo do acesso (só pelo app).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_txObservacao",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_observacao",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da observação"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "tabela": {
                    "type": "string",
                    "description": "Nome da tabela do sistema a que a observação se refere (ex.: ordem)."
                  },
                  "id": {
                    "type": "integer",
                    "description": "Id do registro nessa tabela."
                  },
                  "observacao": {
                    "type": "string",
                    "description": "Texto"
                  },
                  "ativo": {
                    "type": "boolean",
                    "description": "true/false"
                  }
                }
              },
              "example": {
                "observacao": "Texto corrigido"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "delete": {
        "tags": [
          "Cadastros"
        ],
        "summary": "Desativa uma observação",
        "description": "Grava e consulta observações (texto) ligadas a qualquer registro do sistema, identificado por tabela + id. GET por id_tx_observacao devolve uma; por tabela + id devolve a lista. DELETE desativa (ativo = N). A API não verifica se a tabela e o id existem e não restringe pelo escopo do acesso (só pelo app).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "delete_txObservacao",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_observacao",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da observação"
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/supervisorio": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Configuração dos equipamentos (padrão) ou ordens a operar (acao=ORDEM)",
        "description": "Endpoint principal do programa Supervisório instalado no terminal. GET baixa a configuração dos equipamentos e a lista de ordens a operar; POST envia o que aconteceu no pátio (resultado das ordens, senhas, eventos, medições de tanque, pesagens). ORDEM, SENHA e TANQUE são guardados e processados depois pelo PetroW (encerrantes, temperatura e densidade, senhas dos compartimentos, medições de tanque): o efeito não é imediato. EVENTO e PESO são gravados na hora. Tipos de terceiro aceitos: rede, estabelecimento e pessoa (cliente não).\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `ORDEM`: Ordens dos clientes do app (respeitando o escopo do acesso): tipo C ou D em P (pendente), A (aguardando), O (operação) ou V (vistoria), ou que passaram para F (finalizada) ou C (cancelada) nas últimas 24 h; pendentes há pelo menos 1 minuto e criadas nos últimos 7 dias. Inclui também as ordens de ajuste com automação = S em A, O, P ou V. Uma linha por item (compartimento/sequência) da ordem; ordem sem item vem numa linha só. Devolve também 'cancela_ordens_outros_sistemas' (parâmetro do app SUPERVISORIO_CANCELA_ORDENS_INICIADAS_OUTROS_SISTEMAS = S) e 'situacao' com a contagem de ordens do dia (pendente, aguardando, operacao, finalizada e cancelada hoje).\n- `CONFIG (padrão)`: Configuração para o Supervisório: 'operador' (lista de operadores ativos) e 'equipamento', com uma lista por tipo: danload6000, zlx9000, zlxsgt, metroval, multiload, dayler, tanque, veeder_root, motherwell_concentrador, motherwell_radar, joyo_concentrador, joyo_radar, balanca, automacao, impressora, cancela, camera, letreiro. Cada lista traz os equipamentos ativos do app (filtráveis por grupo). Não restringe pelo escopo do acesso (traz o app inteiro). Inclui as credenciais dos equipamentos configurados. Com acesso de perfil filial (ou rede), cada lista de equipamentos traz só os da filial (ou da rede) do acesso; os operadores são do app e vêm todos.",
        "operationId": "get_supervisorio",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ORDEM = lista de ordens; qualquer outro valor ou ausente = configuração (CONFIG). Não diferencia maiúsculas."
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Só acao=ORDEM: C (carregamento), D (descarregamento) ou * (ambos, padrão)."
          },
          {
            "name": "filtro_senha",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Só acao=ORDEM: S = só itens SEM senha gerada, C = só COM senha, * = todos (padrão)."
          },
          {
            "name": "grupo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Grupo de automação do equipamento. Omitido ou '*' = todos os ativos do app. Vazio não equivale a todos: filtra os equipamentos sem grupo."
          },
          {
            "name": "id_operador",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Só na configuração: filtra um operador. Ausente = todos os operadores ativos com alguma senha de equipamento."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_ordem": 123456,
                      "tipo": "C",
                      "modal": "R",
                      "id_ordem_item": 987654,
                      "compartimento": 1,
                      "sequencia": 1,
                      "nivel": 1,
                      "id_cliente": 100,
                      "cliente": "DISTRIBUIDORA A - CIDADE/UF",
                      "id_veiculo": 200,
                      "veiculo": "ABC1D23 (TANQUE)",
                      "placa_veiculo": "ABC1D23",
                      "id_motorista": 300,
                      "motorista": "MOTORISTA 01 CIDADE/UF 000.***.***-00 00000000000",
                      "motorista_nome": "MOTORISTA 01",
                      "motorista_cpf_cnpj": "00000000000",
                      "motorista_registro_cnh": "00000000000",
                      "motorista_categoria_cnh": "E",
                      "motorista_validade_cnh": "2027-12-31",
                      "transportadora_nome": "TRANSPORTADORA EXEMPLO",
                      "transportadora_cpf_cnpj": "00000000000100",
                      "id_produto": 5,
                      "produto": "S10A",
                      "senha": "1234",
                      "quantidade": 5000,
                      "situacao": "A",
                      "medidor_tabela": "metroval",
                      "medidor_id": 3
                    }
                  ],
                  "cancela_ordens_outros_sistemas": false,
                  "situacao": {
                    "pendente": 4,
                    "aguardando": 2,
                    "operacao": 1,
                    "finalizada": 10,
                    "cancelada": 0
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Envio de resultados do pátio por ?acao= (ORDEM padrão, SENHA, EVENTO, TANQUE, PESO)",
        "description": "Endpoint principal do programa Supervisório instalado no terminal. GET baixa a configuração dos equipamentos e a lista de ordens a operar; POST envia o que aconteceu no pátio (resultado das ordens, senhas, eventos, medições de tanque, pesagens). ORDEM, SENHA e TANQUE são guardados e processados depois pelo PetroW (encerrantes, temperatura e densidade, senhas dos compartimentos, medições de tanque): o efeito não é imediato. EVENTO e PESO são gravados na hora. Tipos de terceiro aceitos: rede, estabelecimento e pessoa (cliente não).\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `ORDEM (padrão)`: Guarda o corpo para processamento posterior (um registro por id_ordem; só regrava se o conteúdo mudou). O processamento gera os encerrantes, o histórico de bateladas, o operador e o preset nos itens e atualiza volume, temperatura e densidade da ordem. Erro id_ordem 'Inválido' se ≤ 0 ou fora do escopo.\n- `SENHA`: Guarda o corpo para processamento posterior; o processamento (só de envios das últimas 6 h) grava as senhas dos compartimentos.\n- `EVENTO`: Grava na hora cada item de 'eventos' como evento do app. Corpo inválido dá erro 500.\n- `TANQUE`: Guarda o corpo para processamento posterior; o processamento (só de envios das últimas 6 h) gera as medições de tanque.\n- `PESO`: Pesagem de balança: descarta (tipo X) as pesagens anteriores da placa com o mesmo tipo, grava a nova e procura a ordem da placa. Se a ordem está em A (aguardando), a pesagem é do tipo I e a balança tem 'entrar em operação' = S, a ordem passa para O (operação). Se está em O (operação) ou V (vistoria), a pesagem é do tipo F e a balança tem 'finalizar ordem' = S, a ordem é finalizada. Bloqueio por temperatura não desfaz a pesagem: devolve situacao 'ORDEM NÃO FINALIZADA' + {\"errors\":{\"ordem\": …}} com o motivo (e registra um evento).",
        "operationId": "post_supervisorio",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ORDEM (padrão), SENHA, EVENTO, TANQUE ou PESO. Outro valor dá erro acao 'Inválida'."
          },
          {
            "name": "id_ordem",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "acao=ORDEM: obrigatório (> 0 e dentro do escopo do acesso)."
          },
          {
            "name": "id_balanca",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "acao=PESO: obrigatório (> 0)."
          },
          {
            "name": "peso",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number"
            },
            "description": "acao=PESO: obrigatório (> 0), em kg."
          },
          {
            "name": "placa",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "acao=PESO: obrigatório. Placa válida (pontuação e espaços são retirados; letras convertidas para maiúsculas)."
          },
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "acao=PESO: obrigatório. I = pesagem inicial, F = final, A = balança única de entrada e saída (o PetroW decide: se a última pesagem válida da placa foi I, esta é F; senão, I)."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "(ORDEM) id_ordem": {
                    "type": "integer",
                    "description": "Precisa ser igual ao id_ordem da query; se for diferente, o envio é ignorado no processamento."
                  },
                  "(ORDEM) id_cliente / id_veiculo / id_motorista": {
                    "type": "integer",
                    "description": "Gravados como encerrantes da ordem."
                  },
                  "(ORDEM) data_hora_inicio / data_hora_fim": {
                    "type": "string",
                    "format": "date-time",
                    "description": "Início e fim do preset da ordem, 'AAAA-MM-DD HH:MM:SS'."
                  },
                  "(ORDEM) compartimentos[]": {
                    "type": "array",
                    "items": {},
                    "description": "Um objeto por compartimento: id_ordem_item, id_operador, identificador, compartimento, sequencia, quantidade_programada, quantidade_carregada, quantidade_pendente, data_hora_inicio, data_hora_parada, identificador_integracao (ex.: METROVAL) e identificador_id (id do medidor), e por produto (b100, s500a, s10a, eh, ea, gasa): <produto>_contador_inicial, <produto>_contador_final, <produto>_temperatura, <produto>_densidade (kg/m³ ou g/cm³; > 2 é dividido por 1000). Opcional bateladas[]: batelada (nº), id_operador, data_hora_inicio, data_hora_parada, quantidade_programada/carregada/pendente e por produto _temperatura, _densidade, _vazao, _contador_inicial, _contador_final."
                  },
                  "(SENHA) data[]": {
                    "type": "array",
                    "items": {},
                    "description": "Objetos {id_ordem, compartimento, sequencia, senha}: grava a senha do compartimento e marca a ordem com automacao = S (ordem de ajuste pendente passa para operação)."
                  },
                  "(EVENTO) eventos[]": {
                    "type": "array",
                    "items": {},
                    "description": "Objetos {tabela, id, tipo, evento, data_hora 'AAAA-MM-DD HH:MM:SS'} gravados como eventos do app (todos ou nenhum)."
                  },
                  "(TANQUE) data[]": {
                    "type": "array",
                    "items": {},
                    "description": "Objetos {id_tanque, ultima_medicao 'AAAA-MM-DD HH:MM:SS', nivel_mm, volume_ambiente, volume_a20, temperatura, densidade}: viram medições do tanque (altura = nivel_mm/10 se o tanque usa arqueação; temperatura e densidade vêm da automação ou da tabela do produto, conforme o cadastro do tanque)."
                  },
                  "(PESO)": {
                    "type": "string",
                    "description": "Sem corpo: tudo vai na query."
                  }
                },
                "required": [
                  "(ORDEM) id_ordem",
                  "(ORDEM) data_hora_inicio / data_hora_fim",
                  "(ORDEM) compartimentos[]",
                  "(SENHA) data[]",
                  "(EVENTO) eventos[]",
                  "(TANQUE) data[]"
                ]
              },
              "example": {
                "id_ordem": 123456,
                "id_cliente": 100,
                "id_veiculo": 200,
                "id_motorista": 300,
                "data_hora_inicio": "2026-11-12 08:00:00",
                "data_hora_fim": "2026-11-12 08:25:00",
                "compartimentos": [
                  {
                    "id_ordem_item": 987654,
                    "id_operador": 10,
                    "identificador": "BRACO 1",
                    "compartimento": 1,
                    "sequencia": 1,
                    "quantidade_programada": 5000,
                    "quantidade_carregada": 5000,
                    "quantidade_pendente": 0,
                    "data_hora_inicio": "2026-11-12 08:02:00",
                    "data_hora_parada": "2026-11-12 08:20:00",
                    "identificador_integracao": "METROVAL",
                    "identificador_id": 3,
                    "s10a_contador_inicial": 1000000,
                    "s10a_contador_final": 1005000,
                    "s10a_temperatura": 24.5,
                    "s10a_densidade": 0.835
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/danload6000": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Configuração (padrão), ordens (acao=ORDEM) ou portas seriais (acao=SERIAL)",
        "description": "**Obsoleto**: mantido para equipamentos antigos; use supervisorio. Versão anterior ao Supervisório, para plataformas com Danload 6000. GET traz a configuração dos Danload ou as ordens de carregamento; PUT envia o resultado das ordens, que o PetroW processa depois (convertendo os volumes para 20 °C). O PUT não verifica o escopo do acesso nas ordens do corpo. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `(padrão)`: data[] com os Danload 6000 ativos do app que têm porta serial ativa: id_danload6000, identificador, slave_id, date_rate, port_serial_name, data_byte, stop_byte, parity, <produto>_medidor/_receita/_id, quantidade_minima, calibracao, num_comps, ativo.\n- `ORDEM`: Mesma lista de supervisorio?acao=ORDEM, só com carregamento (tipo C), todas as senhas (filtro *) e o escopo do acesso. Sem 'situacao' e sem 'cancela_ordens_outros_sistemas'.\n- `SERIAL`: Portas seriais ativas, cada uma com os Danload 6000 ligados a ela (danloads[]). Sem porta_serial, lista todas; com perfil filial (ou rede), só as da filial (ou da rede).",
        "operationId": "get_danload6000",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ORDEM, SERIAL ou ausente (configuração)."
          },
          {
            "name": "grupo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Grupo de automação do equipamento. Omitido ou '*' = todos os ativos do app. Vazio não equivale a todos: filtra os equipamentos sem grupo."
          },
          {
            "name": "porta_serial",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "acao=SERIAL: filtra a porta serial (port_serial_name)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_danload6000": 1,
                      "identificador": "DANLOAD 1",
                      "slave_id": 1,
                      "date_rate": 9600,
                      "port_serial_name": "COM1",
                      "data_byte": 8,
                      "stop_byte": 1,
                      "parity": 0,
                      "s10a_medidor": 1,
                      "s10a_receita": 2,
                      "s10a_id": 5,
                      "quantidade_minima": 500,
                      "calibracao": 1.0,
                      "num_comps": 6,
                      "ativo": "S"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Resultado das ordens carregadas (acao=ORDEM)",
        "description": "**Obsoleto**: mantido para equipamentos antigos; use supervisorio. Versão anterior ao Supervisório, para plataformas com Danload 6000. GET traz a configuração dos Danload ou as ordens de carregamento; PUT envia o resultado das ordens, que o PetroW processa depois (convertendo os volumes para 20 °C). O PUT não verifica o escopo do acesso nas ordens do corpo. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `ORDEM`: Guarda cada ordem para processamento posterior (substitui o envio anterior da mesma ordem). Falha numa ordem vira {\"errors\":{\"registro\": …}}.\n- `LOG`: Não implementada: devolve {\"errors\":{\"registro\": \"Falha Função log: Não implementada\"}}.",
        "operationId": "put_danload6000",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ORDEM ou LOG, exatamente assim, em maiúsculas (não há valor padrão). LOG não está implementado."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "<id_ordem>": {
                    "type": "object",
                    "description": "Chave = id da ordem; valor = objeto com compartimentos[]: id_danload6000, produto_1, temperatura_1 (inteiro × 10: 150 = 15,0 °C), densidade_1, volume_1 e, para o segundo produto, produto_2, temperatura_2, densidade_2 e volume_2."
                  }
                },
                "required": [
                  "<id_ordem>"
                ]
              },
              "example": {
                "123456": {
                  "compartimentos": [
                    {
                      "id_danload6000": 1,
                      "produto_1": 2,
                      "temperatura_1": 245,
                      "densidade_1": 0.835,
                      "volume_1": 5000,
                      "produto_2": 0
                    }
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/zlx9000": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Lista dos ZLX9000 ativos",
        "description": "Devolve os ZLX9000 ativos do app (não usa acao). É a mesma lista zlx9000 de equipamento na configuração do supervisorio. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "get_zlx9000",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "grupo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Grupo de automação do equipamento. Omitido ou '*' = todos os ativos do app. Vazio não equivale a todos: filtra os equipamentos sem grupo."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_zlx9000": 1,
                      "id_tx_app": 1,
                      "id_tx_estabelecimento": 10,
                      "ip": "192.168.0.10",
                      "porta": 502,
                      "estacao": 1,
                      "identificador": "ZLX 1",
                      "s10a_medidor": 1,
                      "s10a_receita": 2,
                      "s10a_id": 5,
                      "quantidade_minima": 500,
                      "calibracao": 1.0,
                      "finaliza_ordem": "S",
                      "ativo": "S"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/dayler": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Listas por ?acao= (GRAVAR padrão, LER, CANCELAR, SENHA)",
        "description": "Usado pelo integrador da automação Dayler, só para ordens de carregamento dos clientes do app (respeitando o escopo do acesso). Fluxo: GET GRAVAR lista as ordens ainda não enviadas à automação → PUT GRAVAR envia os tickets (viram as senhas dos compartimentos e a ordem fica com automacao = S) → GET LER lista as ordens em operação já na automação → PUT LER envia o resultado (processado depois pelo PetroW) → GET e PUT CANCELAR tratam as canceladas. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `GRAVAR`: Ordens C (carregamento) com automacao = N em P (pendente), A (aguardando) ou O (operação), pendentes há pelo menos 1 minuto. Resposta 'gravar': objeto com chave = id_ordem e valor = lista de itens {cliente, veiculo (placa), motorista (primeiro nome), produto (código de automação), quantidade, lacre ('')}.\n- `LER`: data[] {id_ordem} das ordens C em O (operação), com automacao = S, que entraram na fila (aguardando) nos últimos 3 dias.\n- `CANCELAR`: data[] {id_ordem} das ordens C canceladas nas últimas 4 horas.\n- `SENHA`: Ordens C em P, A ou O com senha no compartimento 1, nível 1. Resposta 'senha': chave = id_ordem, valor = lista {cliente, veiculo, motorista, compartimento ('C<n>N<nível>'), produto, quantidade, senha}. Atenção: a consulta marca essas ordens com senha = 'N'; consultar de novo não as traz mais.",
        "operationId": "get_dayler",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "GRAVAR (padrão), LER, CANCELAR ou SENHA. Não diferencia maiúsculas."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "gravar": {
                    "123456": [
                      {
                        "cliente": "DISTRIBUIDORA A - CIDADE/UF",
                        "veiculo": "ABC1D23",
                        "motorista": "MOTORISTA",
                        "produto": "S10A",
                        "quantidade": 5000,
                        "lacre": ""
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Retorno da automação por ?acao= (GRAVAR padrão, LER, CANCELAR)",
        "description": "Usado pelo integrador da automação Dayler, só para ordens de carregamento dos clientes do app (respeitando o escopo do acesso). Fluxo: GET GRAVAR lista as ordens ainda não enviadas à automação → PUT GRAVAR envia os tickets (viram as senhas dos compartimentos e a ordem fica com automacao = S) → GET LER lista as ordens em operação já na automação → PUT LER envia o resultado (processado depois pelo PetroW) → GET e PUT CANCELAR tratam as canceladas. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `GRAVAR`: Grava a senha de cada compartimento (um ticket por item) e marca a ordem com automacao = S. Mais itens do que tickets dá erro 500; senha já gravada também dá erro 500.\n- `LER`: Guarda o JSON para processamento posterior pelo PetroW, quando o conteúdo mudou.\n- `CANCELAR`: Volta a ordem para automacao = N.",
        "operationId": "put_dayler",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "GRAVAR (padrão), LER ou CANCELAR."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "(GRAVAR) ordens[0].ordem": {
                    "type": "integer",
                    "description": "Id da ordem (só o primeiro elemento de 'ordens' é lido)."
                  },
                  "(GRAVAR) ordens[0].tickets[]": {
                    "type": "array",
                    "items": {},
                    "description": "Tickets, na ordem dos compartimentos (sequência, compartimento) dos itens com nível, quantidade e produto. Cada ticket vira a senha de um compartimento. Descarregamento: só o primeiro ticket."
                  },
                  "(LER) data": {
                    "type": "object",
                    "description": "JSON do Dayler da ordem: ordem (id), veiculo, cliente, motorista, status, data_hora_entrada, produtos[] (composto_a/composto_b com ticket, quantidade_solicitada, quantidade_carregada, temperatura, densidade, inpm, medidor, lacre, status…). Guardado inteiro, se mudou desde o último envio."
                  },
                  "(CANCELAR) ordens[0]": {
                    "type": "integer",
                    "description": "Id da ordem que volta para automacao = N."
                  }
                },
                "required": [
                  "(GRAVAR) ordens[0].ordem",
                  "(GRAVAR) ordens[0].tickets[]",
                  "(LER) data",
                  "(CANCELAR) ordens[0]"
                ]
              },
              "example": {
                "ordens": [
                  {
                    "ordem": 123456,
                    "tickets": [
                      1001,
                      1002,
                      1003
                    ]
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/totem": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Etapas de conferência por ?acao= (motorista, ordem), em minúsculas",
        "description": "O motorista digita o CPF (GET acao=motorista), depois o número da ordem (GET acao=ordem) e confirma (POST). A confirmação coloca a ordem na fila de agendamento e, se o app tem o parâmetro TOTEM_IMPRESSORA > 0, cria junto o trabalho de impressão do ticket (com os materiais da ordem quando TOTEM_IMPRIMIR_MATERIAIS = S). Só ordens em P (pendente) de carregamento ou descarregamento do motorista do CPF; acesso com perfil filial só vê as ordens da filial. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `motorista`: Só valida: CPF válido e com pelo menos uma ordem pendente de carregamento ou descarregamento no app e no escopo do acesso. Resposta sem dados (só status).\n- `ordem`: Devolve a ordem pendente do CPF: data[] (id_ordem, tipo, situacao, id_transportadora, data_hora_pendente, validade_inicial, validade_final, cliente, motorista, transportadora, placa), produtos_detalhe[] {produto, quantidade}, estabelecimento [nome, logradouro, 'cidade - UF'] do app e, com TOTEM_IMPRIMIR_MATERIAIS = S, materiais[] {tipo (FRASCO, ADITIVO, MARCADOR ou LACRE), descricao, quantidade, unidade}.",
        "operationId": "get_totem",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "motorista ou ordem, exatamente em minúsculas. Outro valor dá erro acao 'Ação inválida'."
          },
          {
            "name": "cpf",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "CPF do motorista, só números (comparado com o cadastro)."
          },
          {
            "name": "id_ordem",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "acao=ordem: obrigatório."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_ordem": 123456,
                      "tipo": "C",
                      "situacao": "P",
                      "id_transportadora": 50,
                      "data_hora_pendente": "2026-11-12 07:30:00",
                      "validade_inicial": "2026-11-12 00:00:00",
                      "validade_final": "2026-11-12 23:59:59",
                      "cliente": "DISTRIBUIDORA A LTDA",
                      "motorista": "MOTORISTA 01",
                      "transportadora": "TRANSPORTADORA EXEMPLO",
                      "placa": "ABC1D23"
                    }
                  ],
                  "produtos_detalhe": [
                    {
                      "produto": "OLEO DIESEL S10",
                      "quantidade": 5000
                    }
                  ],
                  "estabelecimento": [
                    "TERMINAL EXEMPLO",
                    "RUA EXEMPLO, 100",
                    "CIDADE - UF"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "post": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Coloca a ordem na fila (e imprime o ticket)",
        "description": "O motorista digita o CPF (GET acao=motorista), depois o número da ordem (GET acao=ordem) e confirma (POST). A confirmação coloca a ordem na fila de agendamento e, se o app tem o parâmetro TOTEM_IMPRESSORA > 0, cria junto o trabalho de impressão do ticket (com os materiais da ordem quando TOTEM_IMPRIMIR_MATERIAIS = S). Só ordens em P (pendente) de carregamento ou descarregamento do motorista do CPF; acesso com perfil filial só vê as ordens da filial. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "post_totem",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "origem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ordem. Os valores pedido e contrato_coleta são aceitos, mas não fazem nada; outro valor dá erro."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem."
          },
          {
            "name": "cpf_motorista",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "CPF do motorista. Se informado, a ordem precisa ser dele."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/balanca": {
      "put": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Valida ordem (acao=VALIDAR_ORDEM, padrão)",
        "description": "PUT verifica se a ordem pode passar na balança. GET não faz nada (devolve só status ok): a configuração das balanças vem na configuração do supervisorio e a pesagem é enviada por supervisorio?acao=PESO. Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.\n\n**Ações** (`acao` na query):\n- `VALIDAR_ORDEM`: 'ORDEM VÁLIDA' se a ordem é de descarregamento, está em O (operação), entrou em operação há no máximo OPERACAO_DESCARREGAMENTO_CARENCIA minutos (parâmetro do app), está dentro da validade e no escopo do acesso. Caso contrário, 'ORDEM NÃO ENCONTRADA'.",
        "operationId": "put_balanca",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "acao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "VALIDAR_ORDEM (padrão). Qualquer outra ação responde ok, sem dados."
          },
          {
            "name": "id_ordem",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Ordem a validar."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "situacao": "ORDEM VÁLIDA"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/cancela": {
      "put": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Pedido de abertura da cancela",
        "description": "O leitor da cancela envia o número da ordem lido no QR Code. Na ENTRADA, abre se a ordem já está em O (operação) dentro da carência; senão, se ela está em A (aguardando), já foi chamada na fila e a cancela tem 'entrar em operação' = S, coloca em operação todas as ordens abertas do mesmo veículo e motorista. Na SAÍDA, abre se a ordem foi finalizada dentro da carência; senão, se a cancela tem 'finalizar ordem' = S, finaliza as ordens em O (operação) ou V (vistoria) do mesmo veículo e motorista. Cada leitura com id_cancela fica registrada (liberada ou negada, com o motivo). Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "put_cancela",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "qrcode",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Id da ordem lido no QR Code."
          },
          {
            "name": "cancela",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ENTRADA ou SAÍDA (aceita SAIDA; não diferencia maiúsculas e minúsculas)."
          },
          {
            "name": "id_cancela",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Cancela física (cadastro). Define se a leitura coloca a ordem em operação ou a finaliza, e é necessária para registrar a leitura."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "abrir": "SIM",
                  "mensagem": ""
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/camera": {
      "post": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Leitura de placa",
        "description": "POST recebe o evento da câmera (repassado pelo Supervisório), grava a leitura e guarda a foto nos documentos do PetroW. A câmera é localizada pelo device_id ou pelo identificador do cadastro (câmera ativa); sem cadastro, a leitura é gravada com id_camera 0. GET não implementado (501). Tipos de terceiro: rede, estabelecimento e pessoa.\n\n**Perfis**: App, Rede, Filial, Pessoa.",
        "operationId": "post_camera",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "pessoa"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cameraId": {
                    "type": "string",
                    "description": "device_id (ou identificador) da câmera cadastrada."
                  },
                  "dataHoraEvento": {
                    "type": "string",
                    "format": "date-time",
                    "description": "'AAAA-MM-DDTHH:MM:SS' ou com espaço no lugar do T. Valor inválido fica vazio."
                  },
                  "placa": {
                    "type": "string",
                    "description": "Placa lida"
                  },
                  "placaDetectada": {
                    "type": "boolean",
                    "description": "true = S."
                  },
                  "cor": {
                    "type": "string"
                  },
                  "tipoVeiculo": {
                    "type": "string"
                  },
                  "velocidade": {
                    "type": "integer"
                  },
                  "direcao": {
                    "type": "string"
                  },
                  "fotoBase64": {
                    "type": "string",
                    "description": "JPEG em base64."
                  }
                }
              },
              "example": {
                "cameraId": "CAM-ENTRADA-01",
                "dataHoraEvento": "2026-11-12T08:01:15",
                "placa": "ABC1D23",
                "placaDetectada": true,
                "cor": "BRANCO",
                "tipoVeiculo": "CAMINHAO",
                "velocidade": 5,
                "direcao": "ENTRADA",
                "fotoBase64": "/9j/4AAQ..."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "id_camera_leitura": 5001,
                  "id_camera": 3
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/impressoraJob": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Trabalhos pendentes da impressora",
        "description": "Usado pelo Supervisório (impressora cadastrada no PetroW): GET busca os trabalhos pendentes de uma impressora e PUT marca a situação depois de imprimir. Os trabalhos são criados pelo próprio PetroW (ex.: ticket do totem). POST e DELETE existem, mas não fazem nada. Vale para todos os tipos de terceiro (rede, estabelecimento, cliente e pessoa).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_impressoraJob",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_impressora",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Impressora (sem ela, não retorna nada)."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok",
                  "data": [
                    {
                      "id_tx_impressora_job": 900,
                      "id_tx_impressora": 2,
                      "documento": "<conteúdo a imprimir>",
                      "id_tx_pessoa": 0,
                      "data_hora": "2026-11-12 08:00:00",
                      "data_hora_situacao": "2026-11-12 08:00:00",
                      "situacao": "P"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      },
      "put": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Atualiza a situação do trabalho",
        "description": "Usado pelo Supervisório (impressora cadastrada no PetroW): GET busca os trabalhos pendentes de uma impressora e PUT marca a situação depois de imprimir. Os trabalhos são criados pelo próprio PetroW (ex.: ticket do totem). POST e DELETE existem, mas não fazem nada. Vale para todos os tipos de terceiro (rede, estabelecimento, cliente e pessoa).\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "put_impressoraJob",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "parameters": [
          {
            "name": "id_tx_impressora_job",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Trabalho."
          },
          {
            "name": "situacao",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Nova situação: P (pendente), E (enviado), F (finalizado) ou C (cancelado). O valor não é validado: o que chega é gravado. O Supervisório usa F."
          }
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    },
    "/v1/terceiro/status": {
      "get": {
        "tags": [
          "Supervisório e automação"
        ],
        "summary": "Responde ok se a credencial é válida",
        "description": "Não consulta nada: só confirma que a autenticação (APP/REDE/CNPJ/CPF + SENHA + A) e a permissão do terceiro estão corretas. Útil para testar a conexão da integração. Vale para todos os tipos de terceiro.\n\n**Perfis**: App, Rede, Filial, Cliente, Pessoa.",
        "operationId": "get_status",
        "x-perfis": [
          "app",
          "rede",
          "estabelecimento",
          "cliente",
          "pessoa"
        ],
        "responses": {
          "200": {
            "description": "Sucesso",
            "content": {
              "application/json": {
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Erro400"
          },
          "401": {
            "$ref": "#/components/responses/Erro401"
          },
          "403": {
            "$ref": "#/components/responses/Erro403"
          }
        }
      }
    }
  }
}
