{
  "openapi": "3.1.0",
  "info": {
    "title": "API do Precificador 3D",
    "version": "1.0.0-rascunho",
    "summary": "API pública e webhooks do Precificador 3D (v1).",
    "description": "API REST em JSON para integrar o Precificador 3D com loja virtual, ERP, planilhas e\nferramentas como n8n, Zapier e Make.\n\n**Status:** rascunho de 03/10/2026. Especificação completa em\n`docs/novas-funcoes/api-e-webhooks.md`. Nada implementado.\n\n**Convenções**\n- Valores em dinheiro em **centavos** (inteiro). Datas em ISO 8601 com fuso.\n- A conta vem **só da chave**. Nenhuma rota aceita `conta_id`.\n- Campos desconhecidos no corpo e na query são recusados (`400 campo_desconhecido`).\n- Campos de custo, margem e valor só aparecem com o escopo `produtos:custos` **e** a\n  permissão `custos.ver` de quem criou a chave. Sem isso, o campo não existe na resposta.\n- Todo `POST` exige `Idempotency-Key`.\n- Listas paginadas por cursor, `limite` de 1 a 100.\n- Erros no formato RFC 9457 (`application/problem+json`).\n- Limites de uso informados nos cabeçalhos `RateLimit-Policy`, `RateLimit` e `Retry-After`.\n- Leituras devolvem `ETag`; `If-None-Match` igual devolve `304` sem gastar a cota mensal.\n",
    "contact": {
      "name": "Precificador 3D",
      "url": "https://precificador3d.com.br/docs/api",
      "email": "dados@precificador3d.com.br"
    },
    "license": {
      "name": "Proprietária",
      "identifier": "LicenseRef-Proprietaria"
    }
  },
  "servers": [
    {
      "url": "https://api.precificador3d.com.br/v1",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "chaveApi": []
    }
  ],
  "tags": [
    {
      "name": "Conta",
      "description": "Diagnóstico da chave e da conta."
    },
    {
      "name": "Catálogo",
      "description": "Produtos, variações, preços por canal e insumos."
    },
    {
      "name": "Estoque",
      "description": "Saldos de peças prontas e de insumos, e movimentos de peças."
    },
    {
      "name": "Cotações",
      "description": "Leitura de cotações e criação em rascunho."
    },
    {
      "name": "Produção",
      "description": "Pedidos de produção."
    },
    {
      "name": "Webhooks",
      "description": "Descoberta dos tipos de evento. Os endpoints são cadastrados pela tela."
    }
  ],
  "paths": {
    "/saude": {
      "get": {
        "operationId": "saude",
        "tags": [
          "Conta"
        ],
        "summary": "Verificar se a API está no ar",
        "description": "Não exige chave e não consome cota. Responde 503 quando a API está desligada ou o disjuntor está aberto.",
        "security": [],
        "responses": {
          "200": {
            "description": "API no ar.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "situacao"
                  ],
                  "properties": {
                    "situacao": {
                      "type": "string",
                      "const": "ok"
                    }
                  }
                },
                "example": {
                  "situacao": "ok"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/conta": {
      "get": {
        "operationId": "obterConta",
        "tags": [
          "Conta"
        ],
        "summary": "Ver a conta, a chave e os limites",
        "description": "Útil para testar a chave e ver os escopos efetivos (escopos da chave que a pessoa que a criou ainda tem permissão para usar).",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Conta da chave.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Conta"
                },
                "example": {
                  "id": "0b8e4c7a-5d2f-4a8e-9c1b-2f3a4b5c6d7e",
                  "nome": "Ateliê Exemplo",
                  "plano": "oficina",
                  "chave": {
                    "id": "9a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d",
                    "nome": "Loja Exemplo",
                    "prefixo": "pc3d_live_EXEMPLO",
                    "escopos": [
                      "produtos:ler",
                      "estoque:ler",
                      "cotacoes:escrever"
                    ],
                    "escopos_efetivos": [
                      "produtos:ler",
                      "estoque:ler",
                      "cotacoes:escrever"
                    ],
                    "expira_em": "2027-10-03T12:00:00-03:00"
                  },
                  "limites": {
                    "rajada_por_segundo": 2,
                    "rajada_capacidade": 10,
                    "leitura_por_minuto": 60,
                    "escrita_por_minuto": 20,
                    "mes": 150000,
                    "mes_usado": 1820
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/canais": {
      "get": {
        "operationId": "listarCanais",
        "tags": [
          "Catálogo"
        ],
        "summary": "Listar canais de venda",
        "description": "Escopo: `produtos:ler`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Canais da conta.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Canal"
                      }
                    }
                  }
                },
                "example": {
                  "dados": [
                    {
                      "id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
                      "nome": "Loja própria",
                      "tipo": "loja",
                      "arredondamento": "cima_90",
                      "ativo": true
                    },
                    {
                      "id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
                      "nome": "Marketplace Exemplo",
                      "tipo": "marketplace",
                      "arredondamento": "cima_90",
                      "ativo": true
                    }
                  ]
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/produtos": {
      "get": {
        "operationId": "listarProdutos",
        "tags": [
          "Catálogo"
        ],
        "summary": "Listar produtos com preço por canal",
        "description": "Escopo: `produtos:ler`. Com `produtos:custos` (e `custos.ver` de quem criou a chave), os\nprodutos trazem custo, preço sugerido, margem e lucro por hora.\n\nCusto: 1 unidade por requisição com `limite` até 25; acima disso, operação cara\n(1 + 1 a cada 25 produtos).\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Ordem"
          },
          {
            "$ref": "#/components/parameters/AtualizadoDesde"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/StatusProduto"
            }
          },
          {
            "name": "categoria_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "sku",
            "in": "query",
            "description": "Igualdade exata.",
            "schema": {
              "type": "string",
              "maxLength": 40
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de produtos.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Produto"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/produtos/{id}": {
      "get": {
        "operationId": "obterProduto",
        "tags": [
          "Catálogo"
        ],
        "summary": "Ver um produto",
        "description": "Escopo: `produtos:ler`. Produto de outra conta responde 404, igual a id inexistente.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Produto.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Produto"
                },
                "examples": {
                  "semCustos": {
                    "$ref": "#/components/examples/ProdutoChaveiro"
                  },
                  "comCustos": {
                    "$ref": "#/components/examples/ProdutoChaveiroComCustos"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "404": {
            "$ref": "#/components/responses/NaoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/insumos/materiais": {
      "get": {
        "operationId": "listarMateriais",
        "tags": [
          "Catálogo"
        ],
        "summary": "Listar materiais e cores",
        "description": "Escopo: `insumos:ler`. Custo por kg só com `produtos:custos`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/AtualizadoDesde"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Página de materiais.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Material"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                },
                "example": {
                  "dados": [
                    {
                      "id": "3e4f5a6b-7c8d-4e9f-0a1b-2c3d4e5f6a7b",
                      "tipo": "PLA",
                      "marca": "Marca Exemplo",
                      "linha": "Silk",
                      "acabamento_cliente": "brilhante",
                      "atualizado_em": "2026-10-01T09:12:00-03:00",
                      "cores": [
                        {
                          "id": "4f5a6b7c-8d9e-4f0a-1b2c-3d4e5f6a7b8c",
                          "codigo": "#015",
                          "nome_cliente": "Dourado",
                          "nome_interno": "Dourado seda",
                          "cor_hex": "#C9A227",
                          "disponivel": true
                        }
                      ]
                    }
                  ],
                  "proximo_cursor": null
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/estoque": {
      "get": {
        "operationId": "listarEstoque",
        "tags": [
          "Estoque"
        ],
        "summary": "Listar saldos de peças prontas",
        "description": "Escopo: `estoque:ler`. Mostra o local próprio e, só para leitura, as lojas do consignado.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Ordem"
          },
          {
            "$ref": "#/components/parameters/AtualizadoDesde"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          },
          {
            "name": "produto_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "variacao_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "local_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de saldos.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/SaldoEstoque"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                },
                "example": {
                  "dados": [
                    {
                      "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                      "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
                      "sku": "CHAV-DRG-AZ",
                      "local": {
                        "id": "7c8d9e0f-1a2b-4c3d-4e5f-6a7b8c9d0e1f",
                        "tipo": "proprio",
                        "nome": "Estoque próprio"
                      },
                      "parte_id": null,
                      "saldo": 42,
                      "atualizado_em": "2026-10-03T08:30:00-03:00"
                    }
                  ],
                  "proximo_cursor": null
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/estoque/movimentos": {
      "post": {
        "operationId": "criarMovimentoEstoque",
        "tags": [
          "Estoque"
        ],
        "summary": "Lançar entrada, saída ou ajuste de peças",
        "description": "Escopo: `estoque:escrever` (quem criou a chave precisa de `estoque_produtos.movimentar`).\nSempre no **local próprio**: remessa e retorno de consignado só pela página do consignado.\nO saldo nunca fica negativo: saída maior que o saldo responde `422 saldo_insuficiente`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NovoMovimentoEstoque"
              },
              "examples": {
                "vendaLoja": {
                  "summary": "Venda na loja virtual",
                  "value": {
                    "tipo": "saida",
                    "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                    "quantidade": 2,
                    "motivo": "venda_loja",
                    "observacao": "Pedido Loja Exemplo #88231"
                  }
                },
                "ajuste": {
                  "summary": "Contagem física",
                  "value": {
                    "tipo": "ajuste",
                    "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                    "contado": 40,
                    "motivo": "correcao"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Movimento lançado.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Idempotencia-Repetida": {
                "$ref": "#/components/headers/IdempotenciaRepetida"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MovimentoEstoque"
                },
                "example": {
                  "id": "8d9e0f1a-2b3c-4d4e-5f6a-7b8c9d0e1f2a",
                  "tipo": "saida",
                  "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                  "parte_id": null,
                  "quantidade": 2,
                  "saldo_antes": 42,
                  "saldo_depois": 40,
                  "motivo": "venda_loja",
                  "criado_em": "2026-10-03T14:02:11-03:00"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "408": {
            "$ref": "#/components/responses/TempoEsgotado"
          },
          "409": {
            "$ref": "#/components/responses/Conflito"
          },
          "413": {
            "$ref": "#/components/responses/CorpoGrandeDemais"
          },
          "415": {
            "$ref": "#/components/responses/TipoNaoSuportado"
          },
          "422": {
            "$ref": "#/components/responses/NaoProcessavel"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/estoque-insumos": {
      "get": {
        "operationId": "listarEstoqueInsumos",
        "tags": [
          "Estoque"
        ],
        "summary": "Listar saldos de insumos",
        "description": "Escopo: `estoque_insumos:ler`. Sem custo.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          },
          {
            "name": "tipo",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/TipoInsumo"
            }
          },
          {
            "name": "abaixo_do_minimo",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de saldos de insumos.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/SaldoInsumo"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                },
                "example": {
                  "dados": [
                    {
                      "insumo": {
                        "tipo": "material_cor",
                        "id": "4f5a6b7c-8d9e-4f0a-1b2c-3d4e5f6a7b8c",
                        "nome": "PLA Silk · #015 Dourado"
                      },
                      "saldo": 320,
                      "unidade": "g",
                      "minimo": 500,
                      "abaixo_do_minimo": true,
                      "atualizado_em": "2026-10-03T11:40:00-03:00"
                    }
                  ],
                  "proximo_cursor": null
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/cotacoes": {
      "get": {
        "operationId": "listarCotacoes",
        "tags": [
          "Cotações"
        ],
        "summary": "Listar cotações",
        "description": "Escopo: `cotacoes:ler`. Traz nome e contato do cliente (dado pessoal: guarde só o necessário).",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Ordem"
          },
          {
            "$ref": "#/components/parameters/AtualizadoDesde"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/StatusCotacao"
            }
          },
          {
            "name": "criado_desde",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de cotações.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/Cotacao"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      },
      "post": {
        "operationId": "criarCotacao",
        "tags": [
          "Cotações"
        ],
        "summary": "Criar cotação em rascunho",
        "description": "Escopo: `cotacoes:escrever` (quem criou a chave precisa de `cotacoes.editar`).\nA cotação nasce **em rascunho**, com o preço calculado no servidor (faixa por quantidade).\nA API não aceita preço, desconto nem custo. Enviar ao cliente continua pelo app.\nOperação de escrita com custo 5.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NovaCotacao"
              },
              "example": {
                "titulo": "Chaveiros evento Loja Exemplo",
                "cliente": {
                  "nome": "Ana Lima",
                  "contato": "ana.lima@example.com"
                },
                "validade": "2026-10-31",
                "observacao": "Pedido pelo formulário da loja.",
                "itens": [
                  {
                    "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
                    "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                    "quantidade": 200
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Cotação criada em rascunho.",
            "headers": {
              "Location": {
                "description": "URL da cotação criada.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Idempotencia-Repetida": {
                "$ref": "#/components/headers/IdempotenciaRepetida"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cotacao"
                },
                "examples": {
                  "rascunho": {
                    "$ref": "#/components/examples/CotacaoRascunho"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "408": {
            "$ref": "#/components/responses/TempoEsgotado"
          },
          "409": {
            "$ref": "#/components/responses/Conflito"
          },
          "413": {
            "$ref": "#/components/responses/CorpoGrandeDemais"
          },
          "415": {
            "$ref": "#/components/responses/TipoNaoSuportado"
          },
          "422": {
            "$ref": "#/components/responses/NaoProcessavel"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/cotacoes/{id}": {
      "get": {
        "operationId": "obterCotacao",
        "tags": [
          "Cotações"
        ],
        "summary": "Ver uma cotação",
        "description": "Escopo: `cotacoes:ler`. Cotação enviada devolve os valores congelados, como a tela.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Cotação.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cotacao"
                },
                "examples": {
                  "aprovada": {
                    "$ref": "#/components/examples/CotacaoAprovada"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "404": {
            "$ref": "#/components/responses/NaoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/cotacoes/{id}/status": {
      "post": {
        "operationId": "mudarStatusCotacao",
        "tags": [
          "Cotações"
        ],
        "summary": "Mudar o status da cotação",
        "description": "Escopo: `cotacoes:status` (quem criou a chave precisa de `cotacoes.enviar`, como na tela).\nNão envia nada ao cliente e não mexe no link.\n\n**Transições permitidas pela API:** `rascunho` → `em_analise`, `aprovada`, `recusada` ou\n`arquivado`; `em_analise` e `enviada` → `aprovada`, `recusada` ou `arquivado`;\n`aprovada` e `recusada` → `arquivado`. Para `enviada`, para `rascunho` e entre\n`aprovada` e `recusada`, só pela tela. Fora disso: `422 transicao_invalida`.\n\n`de` é obrigatório: se o status atual for outro, a resposta é `409 status_mudou` e nada muda.\n\nSair de `rascunho` ou `em_analise` **congela** a cotação (os valores não mudam mais e os\nitens deixam de ser editáveis), igual à tela. Aprovar não cria pedido de produção.\nGera o webhook `cotacao.status_mudou` (e `cotacao.aprovada` ou `cotacao.recusada`) com\n`origem.chave_id` desta chave, para o integrador ignorar o eco. Escrita com custo 2.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NovoStatusCotacao"
              },
              "examples": {
                "aprovar": {
                  "summary": "Cliente aprovou fora do link",
                  "value": {
                    "de": "enviada",
                    "para": "aprovada",
                    "motivo": "Cliente aprovou por e-mail"
                  }
                },
                "arquivar": {
                  "summary": "Cancelar (arquivar) um rascunho",
                  "value": {
                    "de": "rascunho",
                    "para": "arquivado",
                    "motivo": "Pedido cancelado na loja"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Status mudado. Devolve a cotação com o status novo.",
            "headers": {
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Idempotencia-Repetida": {
                "$ref": "#/components/headers/IdempotenciaRepetida"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Cotacao"
                },
                "examples": {
                  "aprovada": {
                    "$ref": "#/components/examples/CotacaoAprovada"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "404": {
            "$ref": "#/components/responses/NaoEncontrado"
          },
          "408": {
            "$ref": "#/components/responses/TempoEsgotado"
          },
          "409": {
            "$ref": "#/components/responses/StatusMudou"
          },
          "413": {
            "$ref": "#/components/responses/CorpoGrandeDemais"
          },
          "415": {
            "$ref": "#/components/responses/TipoNaoSuportado"
          },
          "422": {
            "$ref": "#/components/responses/NaoProcessavel"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/pedidos-producao": {
      "get": {
        "operationId": "listarPedidosProducao",
        "tags": [
          "Produção"
        ],
        "summary": "Listar pedidos de produção",
        "description": "Escopo: `pedidos:ler`. `valor_centavos` só com `produtos:custos` e `custos.ver` ou `producao.receber` de quem criou a chave.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Limite"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/Ordem"
          },
          {
            "$ref": "#/components/parameters/AtualizadoDesde"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          },
          {
            "name": "situacao",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/SituacaoPedido"
            }
          },
          {
            "name": "tipo",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/TipoPedido"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Página de pedidos.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados",
                    "proximo_cursor"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 100,
                      "items": {
                        "$ref": "#/components/schemas/PedidoProducao"
                      }
                    },
                    "proximo_cursor": {
                      "$ref": "#/components/schemas/ProximoCursor"
                    }
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      },
      "post": {
        "operationId": "criarPedidoProducao",
        "tags": [
          "Produção"
        ],
        "summary": "Criar pedido de produção",
        "description": "Escopo: `pedidos:escrever` (quem criou a chave precisa de `producao.planejar`).\n`valor_centavos` só é aceito se quem criou a chave tiver `custos.ver` ou `producao.receber`\ne a chave tiver `produtos:custos`. Item avulso só em pedido de cliente.\nPedido ligado a cotação fica para a v2. Operação de escrita com custo 5.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NovoPedidoProducao"
              },
              "examples": {
                "cliente": {
                  "summary": "Pedido de cliente vindo do ERP",
                  "value": {
                    "tipo": "cliente",
                    "cliente_nome": "Ana Lima",
                    "prazo": "2026-10-20",
                    "prioridade": "normal",
                    "observacao": "Pedido ERP 5521",
                    "itens": [
                      {
                        "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
                        "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                        "quantidade": 200
                      },
                      {
                        "avulso": {
                          "nome": "Suporte de celular personalizado"
                        },
                        "quantidade": 1
                      }
                    ]
                  }
                },
                "estoque": {
                  "summary": "Repor estoque",
                  "value": {
                    "tipo": "estoque",
                    "itens": [
                      {
                        "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
                        "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
                        "quantidade": 35
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Pedido criado.",
            "headers": {
              "Location": {
                "description": "URL do pedido criado.",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Idempotencia-Repetida": {
                "$ref": "#/components/headers/IdempotenciaRepetida"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoProducao"
                },
                "examples": {
                  "cliente": {
                    "$ref": "#/components/examples/PedidoCliente"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "408": {
            "$ref": "#/components/responses/TempoEsgotado"
          },
          "409": {
            "$ref": "#/components/responses/Conflito"
          },
          "413": {
            "$ref": "#/components/responses/CorpoGrandeDemais"
          },
          "415": {
            "$ref": "#/components/responses/TipoNaoSuportado"
          },
          "422": {
            "$ref": "#/components/responses/NaoProcessavel"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/pedidos-producao/{id}": {
      "get": {
        "operationId": "obterPedidoProducao",
        "tags": [
          "Produção"
        ],
        "summary": "Ver um pedido de produção",
        "description": "Escopo: `pedidos:ler`.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Id"
          },
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Pedido.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PedidoProducao"
                },
                "examples": {
                  "cliente": {
                    "$ref": "#/components/examples/PedidoCliente"
                  }
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "400": {
            "$ref": "#/components/responses/RequisicaoInvalida"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "403": {
            "$ref": "#/components/responses/Proibido"
          },
          "404": {
            "$ref": "#/components/responses/NaoEncontrado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    },
    "/tipos-de-evento": {
      "get": {
        "operationId": "listarTiposDeEvento",
        "tags": [
          "Webhooks"
        ],
        "summary": "Listar os tipos de evento de webhook",
        "description": "Qualquer chave válida. Útil para n8n, Zapier e Make montarem a lista de gatilhos.",
        "parameters": [
          {
            "$ref": "#/components/parameters/IfNoneMatch"
          }
        ],
        "responses": {
          "200": {
            "description": "Tipos de evento.",
            "headers": {
              "ETag": {
                "$ref": "#/components/headers/ETag"
              },
              "RateLimit-Policy": {
                "$ref": "#/components/headers/RateLimitPolicy"
              },
              "RateLimit": {
                "$ref": "#/components/headers/RateLimit"
              },
              "Precificador-Requisicao-Id": {
                "$ref": "#/components/headers/RequisicaoId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "dados"
                  ],
                  "properties": {
                    "dados": {
                      "type": "array",
                      "maxItems": 50,
                      "items": {
                        "type": "object",
                        "additionalProperties": false,
                        "required": [
                          "tipo",
                          "descricao"
                        ],
                        "properties": {
                          "tipo": {
                            "$ref": "#/components/schemas/TipoEvento"
                          },
                          "descricao": {
                            "type": "string",
                            "maxLength": 200
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "dados": [
                    {
                      "tipo": "cotacao.aprovada",
                      "descricao": "A cotação passou para Aprovada."
                    },
                    {
                      "tipo": "estoque.baixo",
                      "descricao": "O saldo de um insumo ficou abaixo do mínimo."
                    }
                  ]
                }
              }
            }
          },
          "304": {
            "$ref": "#/components/responses/NaoModificado"
          },
          "401": {
            "$ref": "#/components/responses/NaoAutenticado"
          },
          "429": {
            "$ref": "#/components/responses/LimiteExcedido"
          },
          "500": {
            "$ref": "#/components/responses/ErroInterno"
          },
          "503": {
            "$ref": "#/components/responses/Indisponivel"
          }
        }
      }
    }
  },
  "webhooks": {
    "cotacao.criada": {
      "post": {
        "operationId": "evento_cotacao_criada",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.criada",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "cotacao.enviada": {
      "post": {
        "operationId": "evento_cotacao_enviada",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.enviada",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "cotacao.fechamento_pedido": {
      "post": {
        "operationId": "evento_cotacao_fechamento_pedido",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.fechamento_pedido",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "cotacao.status_mudou": {
      "post": {
        "operationId": "evento_cotacao_status_mudou",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.status_mudou",
        "description": "Toda troca de status da cotação, feita pela tela, pela API, pelo link ou por rotina.\n`dados` traz `id`, `codigo`, `de`, `para` e `origem { via, chave_id }`. Ignore o eco\nquando `origem.chave_id` for a sua chave. Verifique a assinatura como nos outros eventos.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "cotacao.aprovada": {
      "post": {
        "operationId": "evento_cotacao_aprovada",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.aprovada",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "cotacao.recusada": {
      "post": {
        "operationId": "evento_cotacao_recusada",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento cotacao.recusada",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "link.aberto": {
      "post": {
        "operationId": "evento_link_aberto",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento link.aberto",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "pedido_producao.criado": {
      "post": {
        "operationId": "evento_pedido_producao_criado",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento pedido_producao.criado",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "pedido_producao.situacao_mudou": {
      "post": {
        "operationId": "evento_pedido_producao_situacao_mudou",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento pedido_producao.situacao_mudou",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "pedido_producao.concluido": {
      "post": {
        "operationId": "evento_pedido_producao_concluido",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento pedido_producao.concluido",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "estoque.baixo": {
      "post": {
        "operationId": "evento_estoque_baixo",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento estoque.baixo",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "estoque.movimentado": {
      "post": {
        "operationId": "evento_estoque_movimentado",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento estoque.movimentado",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "produto.criado": {
      "post": {
        "operationId": "evento_produto_criado",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento produto.criado",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "produto.atualizado": {
      "post": {
        "operationId": "evento_produto_atualizado",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento produto.atualizado",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "catalogo.atualizado_em_massa": {
      "post": {
        "operationId": "evento_catalogo_atualizado_em_massa",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento catalogo.atualizado_em_massa",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    },
    "webhook.teste": {
      "post": {
        "operationId": "evento_webhook_teste",
        "tags": [
          "Webhooks"
        ],
        "summary": "Evento webhook.teste",
        "description": "O Precificador envia um `POST` para a URL cadastrada. O corpo diz só **o que mudou**;\nreconsulte a `url` para ter o estado atual. Pode chegar repetido e fora de ordem:\ndeduplique pelo `id`.\n\n**Verificação:** calcule `HMAC-SHA256(segredo, \"<t>.<corpo cru>\")` em hexadecimal (a chave do\nHMAC é o segredo inteiro, como aparece na tela, **incluindo o prefixo `whsec_`**, em UTF-8) e\ncompare em tempo constante com cada `v1=` do cabeçalho `Precificador-Assinatura`.\nRecuse se `|agora − t|` passar de 300 segundos.\n\nResponda `2xx` em até 5 segundos. Redirecionamento conta como falha. `410` desliga o endpoint.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookAssinatura"
          },
          {
            "$ref": "#/components/parameters/WebhookEvento"
          },
          {
            "$ref": "#/components/parameters/WebhookEventoId"
          },
          {
            "$ref": "#/components/parameters/WebhookEntregaId"
          },
          {
            "$ref": "#/components/parameters/WebhookTentativa"
          }
        ],
        "requestBody": {
          "$ref": "#/components/requestBodies/Evento"
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/WebhookRecebido"
          },
          "410": {
            "$ref": "#/components/responses/WebhookEndpointRemovido"
          },
          "500": {
            "$ref": "#/components/responses/WebhookFalhaReceptor"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "chaveApi": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "pc3d_live_<43 base64url><6 checksum>",
        "description": "Chave da conta, criada em Configurações › Integrações. Envie só no cabeçalho\n`Authorization: Bearer pc3d_live_…`. Chave em query string é recusada e suspensa.\n"
      }
    },
    "requestBodies": {
      "Evento": {
        "description": "Corpo do evento. Verifique a assinatura sobre o corpo cru, antes do parse, usando como chave do HMAC o segredo inteiro, incluindo o prefixo `whsec_`, em UTF-8.",
        "required": true,
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Evento"
            },
            "examples": {
              "cotacaoAprovada": {
                "summary": "cotacao.aprovada",
                "value": {
                  "id": "7b0c1d2e-3f4a-4b5c-8d6e-7f8a9b0c1d2e",
                  "tipo": "cotacao.aprovada",
                  "versao": "v1",
                  "criado_em": "2026-10-03T14:00:00-03:00",
                  "conta_id": "0b8e4c7a-5d2f-4a8e-9c1b-2f3a4b5c6d7e",
                  "dados": {
                    "objeto": "cotacao",
                    "id": "9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b",
                    "codigo": "COT-0042",
                    "origem": {
                      "via": "link",
                      "chave_id": null
                    }
                  },
                  "url": "https://api.precificador3d.com.br/v1/cotacoes/9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b"
                }
              },
              "cotacaoStatusMudou": {
                "summary": "cotacao.status_mudou (feito por uma chave de API)",
                "value": {
                  "id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
                  "tipo": "cotacao.status_mudou",
                  "versao": "v1",
                  "criado_em": "2026-10-05T09:30:00-03:00",
                  "conta_id": "0b8e4c7a-5d2f-4a8e-9c1b-2f3a4b5c6d7e",
                  "dados": {
                    "objeto": "cotacao",
                    "id": "9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b",
                    "codigo": "COT-0042",
                    "de": "enviada",
                    "para": "aprovada",
                    "origem": {
                      "via": "api",
                      "chave_id": "9a1b2c3d-4e5f-4a6b-8c7d-9e0f1a2b3c4d"
                    }
                  },
                  "url": "https://api.precificador3d.com.br/v1/cotacoes/9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b"
                }
              },
              "estoqueBaixo": {
                "summary": "estoque.baixo",
                "value": {
                  "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
                  "tipo": "estoque.baixo",
                  "versao": "v1",
                  "criado_em": "2026-10-03T11:40:02-03:00",
                  "conta_id": "0b8e4c7a-5d2f-4a8e-9c1b-2f3a4b5c6d7e",
                  "dados": {
                    "objeto": "insumo",
                    "insumo": {
                      "tipo": "material_cor",
                      "id": "4f5a6b7c-8d9e-4f0a-1b2c-3d4e5f6a7b8c"
                    },
                    "abaixo_do_minimo": true
                  },
                  "url": "https://api.precificador3d.com.br/v1/estoque-insumos?abaixo_do_minimo=true"
                }
              },
              "pedidoConcluido": {
                "summary": "pedido_producao.concluido",
                "value": {
                  "id": "2b3c4d5e-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
                  "tipo": "pedido_producao.concluido",
                  "versao": "v1",
                  "criado_em": "2026-10-18T17:22:40-03:00",
                  "conta_id": "0b8e4c7a-5d2f-4a8e-9c1b-2f3a4b5c6d7e",
                  "dados": {
                    "objeto": "pedido_producao",
                    "id": "a0b1c2d3-e4f5-4a6b-8c7d-9e0f1a2b3c4d",
                    "codigo": "OP-0107"
                  },
                  "url": "https://api.precificador3d.com.br/v1/pedidos-producao/a0b1c2d3-e4f5-4a6b-8c7d-9e0f1a2b3c4d"
                }
              }
            }
          }
        }
      }
    },
    "parameters": {
      "WebhookAssinatura": {
        "name": "Precificador-Assinatura",
        "in": "header",
        "required": true,
        "description": "`t=<segundos Unix>,v1=<hex>`; durante a rotação do segredo vêm dois `v1=`.",
        "schema": {
          "type": "string",
          "maxLength": 300
        },
        "example": "t=1759510800,v1=5f2b0c9e1d7a4b3c2e1f0a9b8c7d6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d"
      },
      "WebhookEvento": {
        "name": "Precificador-Evento",
        "in": "header",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/TipoEvento"
        }
      },
      "WebhookEventoId": {
        "name": "Precificador-Evento-Id",
        "in": "header",
        "required": true,
        "description": "Igual ao `id` do corpo. Use para deduplicar.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "WebhookEntregaId": {
        "name": "Precificador-Entrega-Id",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "WebhookTentativa": {
        "name": "Precificador-Tentativa",
        "in": "header",
        "required": true,
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 8
        }
      },
      "Id": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "Limite": {
        "name": "limite",
        "in": "query",
        "description": "Itens por página, de 1 a 100. Acima de 25 conta como operação cara.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "description": "Valor de `proximo_cursor` da página anterior. Opaco.",
        "schema": {
          "type": "string",
          "maxLength": 200,
          "pattern": "^[A-Za-z0-9_-]+$"
        }
      },
      "Ordem": {
        "name": "ordem",
        "in": "query",
        "description": "Ordenação. `-` na frente = decrescente.",
        "schema": {
          "type": "string",
          "enum": [
            "atualizado_em",
            "-atualizado_em",
            "criado_em",
            "-criado_em"
          ],
          "default": "-atualizado_em"
        }
      },
      "AtualizadoDesde": {
        "name": "atualizado_desde",
        "in": "query",
        "description": "Só o que mudou a partir deste instante. Use com `ordem=atualizado_em` para reconciliar depois de webhooks.",
        "schema": {
          "type": "string",
          "format": "date-time"
        }
      },
      "IfNoneMatch": {
        "name": "If-None-Match",
        "in": "header",
        "description": "ETag recebida antes. Se nada mudou, a resposta é `304` e não gasta a cota mensal.",
        "schema": {
          "type": "string",
          "maxLength": 100
        }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "description": "Chave única da operação, guardada por 24 h junto com o hash do corpo, o status e o id\ncriado (sem corpo nem resposta). Repetir com o mesmo corpo devolve o mesmo status e o\nrecurso relido pelo id. A mesma chave com outro corpo responde `422 idempotencia_conflito`.\n",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 64,
          "pattern": "^[A-Za-z0-9_-]+$"
        },
        "example": "loja-pedido-88231"
      }
    },
    "headers": {
      "ETag": {
        "description": "Versão da representação, para `If-None-Match`.",
        "schema": {
          "type": "string"
        },
        "example": "W/\"c3f1a9\""
      },
      "RateLimitPolicy": {
        "description": "Limites que valem para esta chave (draft IETF RateLimit). `q` = quantidade, `w` = janela em segundos.",
        "schema": {
          "type": "string"
        },
        "example": "\"rajada\";q=10;w=1, \"minuto\";q=60;w=60, \"mes\";q=150000;w=2592000"
      },
      "RateLimit": {
        "description": "Situação do limite mais perto de estourar. `r` = restante, `t` = segundos até repor.",
        "schema": {
          "type": "string"
        },
        "example": "\"minuto\";r=42;t=18"
      },
      "RetryAfter": {
        "description": "Segundos até tentar de novo.",
        "schema": {
          "type": "integer",
          "minimum": 1
        },
        "example": 18
      },
      "RequisicaoId": {
        "description": "Identificador da requisição, para o suporte.",
        "schema": {
          "type": "string"
        },
        "example": "req_01HF8Z3K2M9QX"
      },
      "IdempotenciaRepetida": {
        "description": "`true` quando a requisição repetiu uma `Idempotency-Key` já concluída. O corpo traz o estado atual do recurso criado da primeira vez.",
        "schema": {
          "type": "boolean"
        }
      }
    },
    "responses": {
      "WebhookRecebido": {
        "description": "Recebido. Qualquer 2xx vale; o corpo da resposta é ignorado e não é guardado."
      },
      "WebhookEndpointRemovido": {
        "description": "O endpoint não existe mais; o Precificador desliga o cadastro e avisa o dono."
      },
      "WebhookFalhaReceptor": {
        "description": "Falha do receptor (qualquer resposta fora de 2xx, timeout ou redirecionamento); nova tentativa com backoff, até 8."
      },
      "NaoModificado": {
        "description": "Nada mudou desde a ETag informada.",
        "headers": {
          "ETag": {
            "$ref": "#/components/headers/ETag"
          }
        }
      },
      "RequisicaoInvalida": {
        "description": "Dados, filtro, cursor ou cabeçalho inválido.",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/dados_invalidos",
              "title": "Dados inválidos",
              "status": 400,
              "codigo": "dados_invalidos",
              "detail": "Confira os campos indicados.",
              "requisicao_id": "req_01HF8Z3K2M9QX",
              "erros": [
                {
                  "campo": "itens[0].quantidade",
                  "codigo": "fora_da_faixa"
                }
              ]
            }
          }
        }
      },
      "NaoAutenticado": {
        "description": "Chave ausente, malformada, desconhecida, revogada ou expirada (a resposta é a mesma para todos os casos).",
        "headers": {
          "WWW-Authenticate": {
            "schema": {
              "type": "string"
            },
            "example": "Bearer realm=\"precificador3d\""
          },
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/nao_autenticado",
              "title": "Não autenticado",
              "status": 401,
              "codigo": "nao_autenticado",
              "detail": "Envie uma chave válida no cabeçalho Authorization.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "Proibido": {
        "description": "Escopo insuficiente, conta bloqueada, módulo desligado ou chave suspensa.",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/escopo_insuficiente",
              "title": "Escopo insuficiente",
              "status": 403,
              "codigo": "escopo_insuficiente",
              "detail": "Esta chave não tem permissão para esta operação.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "NaoEncontrado": {
        "description": "Não existe nesta conta.",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/nao_encontrado",
              "title": "Não encontrado",
              "status": 404,
              "codigo": "nao_encontrado",
              "detail": "O recurso não existe ou não pertence a esta conta.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "Conflito": {
        "description": "Requisição com a mesma Idempotency-Key ainda em andamento.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/idempotencia_em_andamento",
              "title": "Operação em andamento",
              "status": 409,
              "codigo": "idempotencia_em_andamento",
              "detail": "Uma requisição com esta Idempotency-Key ainda está sendo processada.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "StatusMudou": {
        "description": "O status atual da cotação não é o informado em `de`. Nada mudou. Releia a cotação e decida de novo.",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "examples": {
              "statusMudou": {
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/status_mudou",
                  "title": "O status mudou",
                  "status": 409,
                  "codigo": "status_mudou",
                  "status_atual": "recusada",
                  "detail": "A cotação não está mais no status informado. Nada foi alterado.",
                  "requisicao_id": "req_01HF8Z3K2M9QX"
                }
              },
              "idempotencia": {
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/idempotencia_em_andamento",
                  "title": "Operação em andamento",
                  "status": 409,
                  "codigo": "idempotencia_em_andamento",
                  "detail": "Uma requisição com esta Idempotency-Key ainda está sendo processada.",
                  "requisicao_id": "req_01HF8Z3K2M9QX"
                }
              }
            }
          }
        }
      },
      "TempoEsgotado": {
        "description": "O corpo do POST não chegou inteiro em 5 s.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/tempo_esgotado",
              "title": "Tempo esgotado",
              "status": 408,
              "codigo": "tempo_esgotado",
              "detail": "O corpo da requisição não chegou dentro do prazo. Envie de novo.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "CorpoGrandeDemais": {
        "description": "Corpo acima de 64 KB.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/corpo_grande_demais",
              "title": "Corpo grande demais",
              "status": 413,
              "codigo": "corpo_grande_demais",
              "detail": "O corpo pode ter até 64 KB.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "TipoNaoSuportado": {
        "description": "Só `application/json`.",
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/tipo_nao_suportado",
              "title": "Tipo de conteúdo não suportado",
              "status": 415,
              "codigo": "tipo_nao_suportado",
              "detail": "Envie application/json.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "NaoProcessavel": {
        "description": "Regra de negócio recusou (referência de outra conta ou inexistente, saldo insuficiente, quantidade fora do mínimo ou múltiplo) ou a Idempotency-Key já foi usada com outro corpo (`idempotencia_conflito`).",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "examples": {
              "saldo": {
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/saldo_insuficiente",
                  "title": "Saldo insuficiente",
                  "status": 422,
                  "codigo": "saldo_insuficiente",
                  "detail": "A saída é maior que o saldo do estoque próprio.",
                  "requisicao_id": "req_01HF8Z3K2M9QX"
                }
              },
              "transicao": {
                "summary": "Transição não permitida pela API",
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/transicao_invalida",
                  "title": "Transição não permitida",
                  "status": 422,
                  "codigo": "transicao_invalida",
                  "detail": "Esta troca de status só pode ser feita pela tela do Precificador.",
                  "requisicao_id": "req_01HF8Z3K2M9QX"
                }
              },
              "idempotencia": {
                "summary": "Mesma Idempotency-Key com outro corpo",
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/idempotencia_conflito",
                  "title": "Idempotency-Key reutilizada",
                  "status": 422,
                  "codigo": "idempotencia_conflito",
                  "detail": "Esta Idempotency-Key já foi usada com outro corpo nas últimas 24 horas. Use uma chave nova.",
                  "requisicao_id": "req_01HF8Z3K2M9QX"
                }
              },
              "referencia": {
                "value": {
                  "type": "https://precificador3d.com.br/docs/api/erros/referencia_invalida",
                  "title": "Referência inválida",
                  "status": 422,
                  "codigo": "referencia_invalida",
                  "detail": "Um dos ids informados não existe nesta conta.",
                  "requisicao_id": "req_01HF8Z3K2M9QX",
                  "erros": [
                    {
                      "campo": "itens[0].variacao_id",
                      "codigo": "referencia_invalida"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "LimiteExcedido": {
        "description": "Limite de uso excedido (rajada, minuto, mês ou requisições simultâneas).",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "RateLimit-Policy": {
            "$ref": "#/components/headers/RateLimitPolicy"
          },
          "RateLimit": {
            "$ref": "#/components/headers/RateLimit"
          },
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/limite_excedido",
              "title": "Limite excedido",
              "status": 429,
              "codigo": "limite_excedido",
              "limite": "conta",
              "detail": "Muitas requisições. Tente de novo depois do tempo indicado em Retry-After.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "ErroInterno": {
        "description": "Erro interno. O detalhe fica no log, ligado ao requisicao_id.",
        "headers": {
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/erro_interno",
              "title": "Erro interno",
              "status": 500,
              "codigo": "erro_interno",
              "detail": "Não foi possível concluir. Se persistir, informe o requisicao_id ao suporte.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      },
      "Indisponivel": {
        "description": "API desligada, sob pressão (disjuntor aberto) ou no limite global da plataforma.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "Precificador-Requisicao-Id": {
            "$ref": "#/components/headers/RequisicaoId"
          }
        },
        "content": {
          "application/problem+json": {
            "schema": {
              "$ref": "#/components/schemas/Problema"
            },
            "example": {
              "type": "https://precificador3d.com.br/docs/api/erros/indisponivel",
              "title": "Indisponível",
              "status": 503,
              "codigo": "indisponivel",
              "detail": "A API está temporariamente indisponível. Tente de novo depois do tempo indicado em Retry-After.",
              "requisicao_id": "req_01HF8Z3K2M9QX"
            }
          }
        }
      }
    },
    "schemas": {
      "Problema": {
        "type": "object",
        "description": "RFC 9457 com as extensões `codigo`, `requisicao_id`, `limite` e `erros`.",
        "required": [
          "type",
          "title",
          "status",
          "codigo",
          "requisicao_id"
        ],
        "properties": {
          "type": {
            "type": "string",
            "format": "uri"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": 400,
            "maximum": 599
          },
          "detail": {
            "type": "string"
          },
          "codigo": {
            "type": "string",
            "enum": [
              "dados_invalidos",
              "campo_desconhecido",
              "filtro_desconhecido",
              "cursor_invalido",
              "idempotencia_obrigatoria",
              "chave_na_url",
              "nao_autenticado",
              "escopo_insuficiente",
              "conta_bloqueada",
              "modulo_desligado",
              "chave_suspensa",
              "nao_encontrado",
              "metodo_nao_permitido",
              "idempotencia_em_andamento",
              "status_mudou",
              "conflito",
              "tempo_esgotado",
              "corpo_grande_demais",
              "tipo_nao_suportado",
              "referencia_invalida",
              "saldo_insuficiente",
              "quantidade_invalida",
              "idempotencia_conflito",
              "transicao_invalida",
              "regra_de_negocio",
              "limite_excedido",
              "cota_mensal_excedida",
              "concorrencia_excedida",
              "erro_interno",
              "indisponivel"
            ]
          },
          "requisicao_id": {
            "type": "string"
          },
          "status_atual": {
            "description": "Status atual da cotação (só no 409 status_mudou).",
            "type": "string"
          },
          "limite": {
            "description": "Qual camada estourou (só no 429).",
            "type": "string",
            "enum": [
              "chave",
              "conta",
              "global",
              "ip"
            ]
          },
          "erros": {
            "type": "array",
            "maxItems": 50,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "campo",
                "codigo"
              ],
              "properties": {
                "campo": {
                  "type": "string"
                },
                "codigo": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ProximoCursor": {
        "description": "Cursor da próxima página, ou `null` no fim.",
        "type": [
          "string",
          "null"
        ]
      },
      "Centavos": {
        "type": "integer",
        "minimum": 0,
        "maximum": 100000000000
      },
      "Conta": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "nome",
          "plano",
          "chave",
          "limites"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "nome": {
            "type": "string"
          },
          "plano": {
            "type": "string",
            "enum": [
              "bancada",
              "oficina",
              "farm"
            ]
          },
          "chave": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "nome",
              "prefixo",
              "escopos",
              "escopos_efetivos",
              "expira_em"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "nome": {
                "type": "string",
                "maxLength": 60
              },
              "prefixo": {
                "type": "string",
                "description": "Início da chave, para reconhecer (nunca a chave inteira)."
              },
              "escopos": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Escopo"
                }
              },
              "escopos_efetivos": {
                "description": "Escopos da chave que quem a criou ainda pode usar.",
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Escopo"
                }
              },
              "expira_em": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time"
              }
            }
          },
          "limites": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "rajada_por_segundo",
              "rajada_capacidade",
              "leitura_por_minuto",
              "escrita_por_minuto",
              "mes",
              "mes_usado"
            ],
            "properties": {
              "rajada_por_segundo": {
                "type": "integer"
              },
              "rajada_capacidade": {
                "type": "integer"
              },
              "leitura_por_minuto": {
                "type": "integer"
              },
              "escrita_por_minuto": {
                "type": "integer"
              },
              "mes": {
                "type": "integer"
              },
              "mes_usado": {
                "type": "integer"
              }
            }
          }
        }
      },
      "Escopo": {
        "type": "string",
        "enum": [
          "produtos:ler",
          "produtos:custos",
          "insumos:ler",
          "estoque:ler",
          "estoque:escrever",
          "estoque_insumos:ler",
          "cotacoes:ler",
          "cotacoes:escrever",
          "cotacoes:status",
          "pedidos:ler",
          "pedidos:escrever"
        ]
      },
      "Canal": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "nome",
          "tipo",
          "arredondamento",
          "ativo"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "nome": {
            "type": "string"
          },
          "tipo": {
            "type": "string",
            "enum": [
              "loja",
              "marketplace"
            ]
          },
          "arredondamento": {
            "type": "string",
            "enum": [
              "nenhum",
              "cima_90",
              "cima_inteiro"
            ]
          },
          "ativo": {
            "type": "boolean"
          }
        }
      },
      "StatusProduto": {
        "type": "string",
        "enum": [
          "avaliacao",
          "catalogo",
          "pausado"
        ]
      },
      "Produto": {
        "type": "object",
        "description": "Os campos de custo só existem com `produtos:custos` e `custos.ver` de quem criou a chave.",
        "additionalProperties": false,
        "required": [
          "id",
          "nome",
          "sku",
          "status",
          "categoria",
          "preco_venda_centavos",
          "precos",
          "faixas",
          "variacoes",
          "criado_em",
          "atualizado_em"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "nome": {
            "type": "string",
            "maxLength": 120
          },
          "sku": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          },
          "status": {
            "$ref": "#/components/schemas/StatusProduto"
          },
          "categoria": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "id",
                  "nome"
                ],
                "properties": {
                  "id": {
                    "type": "string",
                    "format": "uuid"
                  },
                  "nome": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "titulo": {
            "type": [
              "string",
              "null"
            ]
          },
          "descricao": {
            "type": [
              "string",
              "null"
            ]
          },
          "ean": {
            "type": [
              "string",
              "null"
            ]
          },
          "medidas": {
            "type": "object",
            "additionalProperties": false,
            "properties": {
              "largura_cm": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "altura_cm": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "profundidade_cm": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "peso_g": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "peso_embalado_g": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "quantidade_minima": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "multiplo_de": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1
          },
          "preco_venda_centavos": {
            "description": "Preço da loja própria definido pela conta, ou null.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/Centavos"
              },
              {
                "type": "null"
              }
            ]
          },
          "precos": {
            "description": "Preço em cada canal ativo, calculado no servidor.",
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "canal_id",
                "canal_nome",
                "preco_centavos"
              ],
              "properties": {
                "canal_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "canal_nome": {
                  "type": "string"
                },
                "preco_centavos": {
                  "$ref": "#/components/schemas/Centavos"
                }
              }
            }
          },
          "faixas": {
            "description": "Preço por unidade conforme a quantidade (vazio quando o produto não tem faixas).",
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "quantidade_a_partir_de",
                "preco_unitario_centavos"
              ],
              "properties": {
                "quantidade_a_partir_de": {
                  "type": "integer",
                  "minimum": 1
                },
                "preco_unitario_centavos": {
                  "$ref": "#/components/schemas/Centavos"
                }
              }
            }
          },
          "variacoes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Variacao"
            }
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          },
          "custo_centavos": {
            "description": "[custos] Custo completo por unidade.",
            "$ref": "#/components/schemas/Centavos"
          },
          "preco_sugerido_centavos": {
            "description": "[custos] Preço sugerido pelo método de preço da conta.",
            "$ref": "#/components/schemas/Centavos"
          },
          "margem_bp": {
            "description": "[custos] Margem em pontos-base (2500 = 25%).",
            "type": "integer"
          },
          "lucro_hora_centavos": {
            "description": "[custos] Lucro por hora de máquina.",
            "type": "integer"
          }
        }
      },
      "Variacao": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "nome",
          "sku",
          "ativa",
          "valores",
          "cor"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "nome": {
            "type": "string"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "ativa": {
            "type": "boolean"
          },
          "valores": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "tipo",
                "valor"
              ],
              "properties": {
                "tipo": {
                  "type": "string"
                },
                "valor": {
                  "type": "string"
                }
              }
            }
          },
          "cor": {
            "oneOf": [
              {
                "type": "null"
              },
              {
                "$ref": "#/components/schemas/CorCliente"
              }
            ]
          }
        }
      },
      "CorCliente": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "codigo",
          "nome_cliente"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "codigo": {
            "type": "string",
            "examples": [
              "#015"
            ]
          },
          "nome_cliente": {
            "type": "string"
          },
          "acabamento": {
            "type": "string",
            "enum": [
              "nenhum",
              "brilhante",
              "fosco"
            ]
          }
        }
      },
      "Material": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "tipo",
          "marca",
          "linha",
          "acabamento_cliente",
          "cores",
          "atualizado_em"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tipo": {
            "type": "string"
          },
          "marca": {
            "type": [
              "string",
              "null"
            ]
          },
          "linha": {
            "type": [
              "string",
              "null"
            ]
          },
          "acabamento_cliente": {
            "type": "string",
            "enum": [
              "nenhum",
              "brilhante",
              "fosco"
            ]
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          },
          "custo_kg_centavos": {
            "description": "[custos]",
            "$ref": "#/components/schemas/Centavos"
          },
          "cores": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "id",
                "codigo",
                "nome_cliente",
                "nome_interno",
                "cor_hex",
                "disponivel"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "codigo": {
                  "type": "string"
                },
                "nome_cliente": {
                  "type": "string"
                },
                "nome_interno": {
                  "type": "string"
                },
                "cor_hex": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "pattern": "^#[0-9A-Fa-f]{6}$"
                },
                "disponivel": {
                  "type": "boolean"
                },
                "custo_kg_centavos": {
                  "description": "[custos] Só quando diferente do material.",
                  "$ref": "#/components/schemas/Centavos"
                }
              }
            }
          }
        }
      },
      "SaldoEstoque": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "variacao_id",
          "produto_id",
          "sku",
          "local",
          "parte_id",
          "saldo",
          "atualizado_em"
        ],
        "properties": {
          "variacao_id": {
            "type": "string",
            "format": "uuid"
          },
          "produto_id": {
            "type": "string",
            "format": "uuid"
          },
          "sku": {
            "type": [
              "string",
              "null"
            ]
          },
          "local": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "tipo",
              "nome"
            ],
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "tipo": {
                "type": "string",
                "enum": [
                  "proprio",
                  "consignatario"
                ]
              },
              "nome": {
                "type": "string"
              }
            }
          },
          "parte_id": {
            "description": "Parte solta guardada; null = peça completa.",
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "saldo": {
            "type": "integer",
            "minimum": 0
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "NovoMovimentoEstoque": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "tipo",
          "variacao_id",
          "motivo"
        ],
        "properties": {
          "tipo": {
            "type": "string",
            "enum": [
              "entrada",
              "saida",
              "ajuste"
            ]
          },
          "variacao_id": {
            "type": "string",
            "format": "uuid"
          },
          "parte_id": {
            "type": "string",
            "format": "uuid"
          },
          "quantidade": {
            "description": "Obrigatória em entrada e saída.",
            "type": "integer",
            "minimum": 1,
            "maximum": 99999
          },
          "contado": {
            "description": "Obrigatório em ajuste (saldo contado).",
            "type": "integer",
            "minimum": 0,
            "maximum": 99999
          },
          "motivo": {
            "type": "string",
            "enum": [
              "venda_loja",
              "venda_marketplace",
              "perda",
              "devolucao",
              "correcao",
              "outro"
            ]
          },
          "observacao": {
            "type": "string",
            "maxLength": 200
          }
        }
      },
      "MovimentoEstoque": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "tipo",
          "variacao_id",
          "parte_id",
          "quantidade",
          "saldo_antes",
          "saldo_depois",
          "motivo",
          "criado_em"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "tipo": {
            "type": "string",
            "enum": [
              "entrada",
              "saida",
              "ajuste"
            ]
          },
          "variacao_id": {
            "type": "string",
            "format": "uuid"
          },
          "parte_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "quantidade": {
            "type": "integer"
          },
          "saldo_antes": {
            "type": "integer",
            "minimum": 0
          },
          "saldo_depois": {
            "type": "integer",
            "minimum": 0
          },
          "motivo": {
            "type": "string"
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TipoInsumo": {
        "type": "string",
        "enum": [
          "material_cor",
          "adicional",
          "embalagem"
        ]
      },
      "SaldoInsumo": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "insumo",
          "saldo",
          "unidade",
          "minimo",
          "abaixo_do_minimo",
          "atualizado_em"
        ],
        "properties": {
          "insumo": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "tipo",
              "id",
              "nome"
            ],
            "properties": {
              "tipo": {
                "$ref": "#/components/schemas/TipoInsumo"
              },
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "nome": {
                "type": "string"
              }
            }
          },
          "saldo": {
            "type": "number",
            "minimum": 0
          },
          "unidade": {
            "type": "string",
            "enum": [
              "g",
              "un"
            ]
          },
          "minimo": {
            "type": [
              "number",
              "null"
            ],
            "minimum": 0
          },
          "abaixo_do_minimo": {
            "type": "boolean"
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "StatusCotacao": {
        "type": "string",
        "enum": [
          "rascunho",
          "enviada",
          "aprovada",
          "recusada",
          "em_analise",
          "arquivado"
        ]
      },
      "Cotacao": {
        "type": "object",
        "description": "Os campos de custo só existem com `produtos:custos` e `custos.ver` de quem criou a chave.",
        "additionalProperties": false,
        "required": [
          "id",
          "codigo",
          "titulo",
          "status",
          "versao",
          "cliente",
          "validade",
          "itens",
          "total_centavos",
          "desconto_centavos",
          "criado_em",
          "atualizado_em"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "codigo": {
            "type": "string"
          },
          "titulo": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/StatusCotacao"
          },
          "versao": {
            "type": "integer",
            "minimum": 1
          },
          "cliente": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "nome",
              "contato"
            ],
            "properties": {
              "nome": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "contato": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "validade": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "condicoes": {
            "type": [
              "string",
              "null"
            ]
          },
          "observacao": {
            "type": [
              "string",
              "null"
            ]
          },
          "itens": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "id",
                "nome",
                "sku",
                "produto_id",
                "variacao_id",
                "quantidade",
                "preco_unitario_centavos",
                "total_centavos",
                "cor",
                "cor_a_combinar"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "nome": {
                  "type": "string"
                },
                "sku": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "produto_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid"
                },
                "variacao_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid"
                },
                "quantidade": {
                  "type": "integer",
                  "minimum": 1
                },
                "preco_unitario_centavos": {
                  "$ref": "#/components/schemas/Centavos"
                },
                "total_centavos": {
                  "$ref": "#/components/schemas/Centavos"
                },
                "cor": {
                  "oneOf": [
                    {
                      "type": "null"
                    },
                    {
                      "$ref": "#/components/schemas/CorCliente"
                    }
                  ]
                },
                "cor_a_combinar": {
                  "type": "boolean"
                }
              }
            }
          },
          "total_centavos": {
            "$ref": "#/components/schemas/Centavos"
          },
          "desconto_centavos": {
            "$ref": "#/components/schemas/Centavos"
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          },
          "enviada_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "aprovada_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "congelada": {
            "description": "true fora de rascunho e em_analise. Congelada, a cotação só se edita voltando para rascunho pela tela.",
            "type": "boolean"
          },
          "custo_total_centavos": {
            "description": "[custos]",
            "$ref": "#/components/schemas/Centavos"
          },
          "lucro_centavos": {
            "description": "[custos]",
            "type": "integer"
          },
          "margem_bp": {
            "description": "[custos] Pontos-base.",
            "type": "integer"
          }
        }
      },
      "NovaCotacao": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "titulo",
          "cliente",
          "itens"
        ],
        "properties": {
          "titulo": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "cliente": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "nome"
            ],
            "properties": {
              "nome": {
                "type": "string",
                "minLength": 1,
                "maxLength": 120
              },
              "contato": {
                "type": "string",
                "maxLength": 160
              }
            }
          },
          "validade": {
            "type": "string",
            "format": "date"
          },
          "observacao": {
            "type": "string",
            "maxLength": 1000
          },
          "itens": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "produto_id",
                "quantidade"
              ],
              "properties": {
                "produto_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "variacao_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "quantidade": {
                  "type": "integer",
                  "minimum": 1,
                  "maximum": 99999
                },
                "cor_id": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            }
          }
        }
      },
      "NovoStatusCotacao": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "de",
          "para"
        ],
        "properties": {
          "de": {
            "$ref": "#/components/schemas/StatusCotacao"
          },
          "para": {
            "type": "string",
            "enum": [
              "em_analise",
              "aprovada",
              "recusada",
              "arquivado"
            ]
          },
          "motivo": {
            "type": "string",
            "maxLength": 200
          }
        }
      },
      "SituacaoPedido": {
        "type": "string",
        "enum": [
          "aberto",
          "em_producao",
          "finalizado",
          "cancelado"
        ]
      },
      "TipoPedido": {
        "type": "string",
        "enum": [
          "cliente",
          "estoque"
        ]
      },
      "PedidoProducao": {
        "type": "object",
        "description": "`valor_centavos` só existe com `produtos:custos` e `custos.ver` ou `producao.receber` de quem criou a chave.",
        "additionalProperties": false,
        "required": [
          "id",
          "codigo",
          "tipo",
          "origem",
          "cotacao_id",
          "cliente_nome",
          "prazo",
          "prioridade",
          "situacao",
          "pagamento_situacao",
          "itens",
          "criado_em",
          "atualizado_em",
          "finalizado_em"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "codigo": {
            "type": "string",
            "pattern": "^OP-[0-9]{4,}$"
          },
          "tipo": {
            "$ref": "#/components/schemas/TipoPedido"
          },
          "origem": {
            "type": "string",
            "enum": [
              "cotacao",
              "manual",
              "repor",
              "api"
            ]
          },
          "cotacao_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "cliente_nome": {
            "description": "null em pedido para estoque e depois da anonimização (LGPD).",
            "type": [
              "string",
              "null"
            ]
          },
          "prazo": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "prioridade": {
            "type": "string",
            "enum": [
              "normal",
              "urgente"
            ]
          },
          "situacao": {
            "$ref": "#/components/schemas/SituacaoPedido"
          },
          "pagamento_situacao": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "nao_pago",
              "sinal_pago",
              "pago",
              null
            ]
          },
          "itens": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "id",
                "tipo",
                "produto_id",
                "variacao_id",
                "nome",
                "quantidade",
                "situacao",
                "etapa"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "format": "uuid"
                },
                "tipo": {
                  "type": "string",
                  "enum": [
                    "catalogo",
                    "cotacao",
                    "avulso"
                  ]
                },
                "produto_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid"
                },
                "variacao_id": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "format": "uuid"
                },
                "nome": {
                  "type": "string"
                },
                "quantidade": {
                  "type": "integer",
                  "minimum": 1
                },
                "situacao": {
                  "type": "string",
                  "enum": [
                    "ativo",
                    "finalizado",
                    "retirado"
                  ]
                },
                "etapa": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "Nome da etapa atual do item."
                }
              }
            }
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "atualizado_em": {
            "type": "string",
            "format": "date-time"
          },
          "finalizado_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "valor_centavos": {
            "description": "[custos] Valor do pedido de cliente.",
            "$ref": "#/components/schemas/Centavos"
          }
        }
      },
      "NovoPedidoProducao": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "tipo",
          "itens"
        ],
        "properties": {
          "tipo": {
            "$ref": "#/components/schemas/TipoPedido"
          },
          "cliente_nome": {
            "description": "Obrigatório em pedido de cliente.",
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "prazo": {
            "description": "Obrigatório em pedido de cliente.",
            "type": "string",
            "format": "date"
          },
          "valor_centavos": {
            "description": "Só aceito com permissão de valor (ver a descrição da operação).",
            "$ref": "#/components/schemas/Centavos"
          },
          "prioridade": {
            "type": "string",
            "enum": [
              "normal",
              "urgente"
            ],
            "default": "normal"
          },
          "observacao": {
            "type": "string",
            "maxLength": 500
          },
          "itens": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "oneOf": [
                {
                  "type": "object",
                  "title": "Item do catálogo",
                  "additionalProperties": false,
                  "required": [
                    "produto_id",
                    "variacao_id",
                    "quantidade"
                  ],
                  "properties": {
                    "produto_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "variacao_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "quantidade": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 99999
                    }
                  }
                },
                {
                  "type": "object",
                  "title": "Item avulso (só em pedido de cliente)",
                  "additionalProperties": false,
                  "required": [
                    "avulso",
                    "quantidade"
                  ],
                  "properties": {
                    "avulso": {
                      "type": "object",
                      "additionalProperties": false,
                      "required": [
                        "nome"
                      ],
                      "properties": {
                        "nome": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 120
                        }
                      }
                    },
                    "quantidade": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 99999
                    }
                  }
                }
              ]
            }
          }
        }
      },
      "TipoEvento": {
        "type": "string",
        "enum": [
          "cotacao.criada",
          "cotacao.enviada",
          "cotacao.fechamento_pedido",
          "cotacao.status_mudou",
          "cotacao.aprovada",
          "cotacao.recusada",
          "link.aberto",
          "pedido_producao.criado",
          "pedido_producao.situacao_mudou",
          "pedido_producao.concluido",
          "estoque.baixo",
          "estoque.movimentado",
          "produto.criado",
          "produto.atualizado",
          "catalogo.atualizado_em_massa",
          "webhook.teste"
        ]
      },
      "Evento": {
        "type": "object",
        "description": "Corpo do webhook. Até 4 KB. Sem dado pessoal, custo ou valor.",
        "additionalProperties": false,
        "required": [
          "id",
          "tipo",
          "versao",
          "criado_em",
          "conta_id",
          "dados",
          "url"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "description": "Use para deduplicar."
          },
          "tipo": {
            "$ref": "#/components/schemas/TipoEvento"
          },
          "versao": {
            "type": "string",
            "const": "v1"
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "conta_id": {
            "type": "string",
            "format": "uuid"
          },
          "dados": {
            "type": "object",
            "description": "Id do objeto e poucos campos. Pode ganhar campos novos sem aviso.",
            "additionalProperties": true,
            "required": [
              "objeto"
            ],
            "properties": {
              "objeto": {
                "type": "string",
                "enum": [
                  "cotacao",
                  "link",
                  "pedido_producao",
                  "insumo",
                  "estoque",
                  "produto",
                  "catalogo",
                  "teste"
                ]
              }
            }
          },
          "url": {
            "description": "Onde reconsultar o estado atual.",
            "type": [
              "string",
              "null"
            ],
            "format": "uri"
          }
        }
      }
    },
    "examples": {
      "ProdutoChaveiro": {
        "summary": "Produto sem campos de custo",
        "value": {
          "id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
          "nome": "Chaveiro Dragão",
          "sku": "CHAV-DRG",
          "status": "catalogo",
          "categoria": {
            "id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
            "nome": "Chaveiros"
          },
          "titulo": "Chaveiro Dragão articulado impresso em 3D",
          "descricao": "Dragão articulado de 12 cm, com argola.",
          "ean": null,
          "medidas": {
            "largura_cm": 12,
            "altura_cm": 3,
            "profundidade_cm": 2,
            "peso_g": 14,
            "peso_embalado_g": 22
          },
          "quantidade_minima": 1,
          "multiplo_de": null,
          "preco_venda_centavos": 1990,
          "precos": [
            {
              "canal_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
              "canal_nome": "Loja própria",
              "preco_centavos": 1990
            },
            {
              "canal_id": "2d3e4f5a-6b7c-4d8e-9f0a-1b2c3d4e5f6a",
              "canal_nome": "Marketplace Exemplo",
              "preco_centavos": 2490
            }
          ],
          "faixas": [
            {
              "quantidade_a_partir_de": 1,
              "preco_unitario_centavos": 1990
            },
            {
              "quantidade_a_partir_de": 35,
              "preco_unitario_centavos": 1290
            }
          ],
          "variacoes": [
            {
              "id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
              "nome": "Azul",
              "sku": "CHAV-DRG-AZ",
              "ativa": true,
              "valores": [
                {
                  "tipo": "Cor",
                  "valor": "Azul"
                }
              ],
              "cor": {
                "id": "c2d3e4f5-a6b7-4c8d-9e0f-1a2b3c4d5e6f",
                "codigo": "#007",
                "nome_cliente": "Azul",
                "acabamento": "fosco"
              }
            }
          ],
          "criado_em": "2026-08-12T10:00:00-03:00",
          "atualizado_em": "2026-10-02T10:00:00-03:00"
        }
      },
      "ProdutoChaveiroComCustos": {
        "summary": "Produto com produtos:custos e custos.ver",
        "value": {
          "id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
          "nome": "Chaveiro Dragão",
          "sku": "CHAV-DRG",
          "status": "catalogo",
          "categoria": {
            "id": "b1c2d3e4-f5a6-4b7c-8d9e-0f1a2b3c4d5e",
            "nome": "Chaveiros"
          },
          "preco_venda_centavos": 1990,
          "precos": [
            {
              "canal_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
              "canal_nome": "Loja própria",
              "preco_centavos": 1990
            }
          ],
          "faixas": [],
          "variacoes": [],
          "criado_em": "2026-08-12T10:00:00-03:00",
          "atualizado_em": "2026-10-02T10:00:00-03:00",
          "custo_centavos": 612,
          "preco_sugerido_centavos": 1850,
          "margem_bp": 6925,
          "lucro_hora_centavos": 1840
        }
      },
      "CotacaoRascunho": {
        "summary": "Cotação recém-criada pela API",
        "value": {
          "id": "9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b",
          "codigo": "COT-0042",
          "titulo": "Chaveiros evento Loja Exemplo",
          "status": "rascunho",
          "versao": 1,
          "cliente": {
            "nome": "Ana Lima",
            "contato": "ana.lima@example.com"
          },
          "validade": "2026-10-31",
          "condicoes": "Pagamento 50% na aprovação e 50% na entrega.",
          "observacao": "Pedido pelo formulário da loja.",
          "itens": [
            {
              "id": "d3e4f5a6-b7c8-4d9e-0f1a-2b3c4d5e6f7a",
              "nome": "Chaveiro Dragão · Azul",
              "sku": "CHAV-DRG-AZ",
              "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
              "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
              "quantidade": 200,
              "preco_unitario_centavos": 1290,
              "total_centavos": 258000,
              "cor": null,
              "cor_a_combinar": false
            }
          ],
          "total_centavos": 258000,
          "desconto_centavos": 0,
          "criado_em": "2026-10-03T14:00:00-03:00",
          "atualizado_em": "2026-10-03T14:00:00-03:00",
          "enviada_em": null,
          "aprovada_em": null
        }
      },
      "CotacaoAprovada": {
        "summary": "Cotação aprovada",
        "value": {
          "id": "9e0f1a2b-3c4d-4e5f-6a7b-8c9d0e1f2a3b",
          "codigo": "COT-0042",
          "titulo": "Chaveiros evento Loja Exemplo",
          "status": "aprovada",
          "versao": 2,
          "cliente": {
            "nome": "Ana Lima",
            "contato": "ana.lima@example.com"
          },
          "validade": "2026-10-31",
          "condicoes": "Pagamento 50% na aprovação e 50% na entrega.",
          "observacao": null,
          "itens": [
            {
              "id": "d3e4f5a6-b7c8-4d9e-0f1a-2b3c4d5e6f7a",
              "nome": "Chaveiro Dragão · Azul",
              "sku": "CHAV-DRG-AZ",
              "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
              "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
              "quantidade": 200,
              "preco_unitario_centavos": 1290,
              "total_centavos": 258000,
              "cor": {
                "id": "c2d3e4f5-a6b7-4c8d-9e0f-1a2b3c4d5e6f",
                "codigo": "#007",
                "nome_cliente": "Azul",
                "acabamento": "fosco"
              },
              "cor_a_combinar": false
            }
          ],
          "total_centavos": 258000,
          "desconto_centavos": 12900,
          "criado_em": "2026-10-03T14:00:00-03:00",
          "atualizado_em": "2026-10-05T09:30:00-03:00",
          "enviada_em": "2026-10-03T16:10:00-03:00",
          "aprovada_em": "2026-10-05T09:30:00-03:00"
        }
      },
      "PedidoCliente": {
        "summary": "Pedido de produção de cliente",
        "value": {
          "id": "a0b1c2d3-e4f5-4a6b-8c7d-9e0f1a2b3c4d",
          "codigo": "OP-0107",
          "tipo": "cliente",
          "origem": "api",
          "cotacao_id": null,
          "cliente_nome": "Ana Lima",
          "prazo": "2026-10-20",
          "prioridade": "normal",
          "situacao": "aberto",
          "pagamento_situacao": "nao_pago",
          "itens": [
            {
              "id": "e4f5a6b7-c8d9-4e0f-1a2b-3c4d5e6f7a8b",
              "tipo": "catalogo",
              "produto_id": "5a6b7c8d-9e0f-4a1b-2c3d-4e5f6a7b8c9d",
              "variacao_id": "6b7c8d9e-0f1a-4b2c-3d4e-5f6a7b8c9d0e",
              "nome": "Chaveiro Dragão · Azul",
              "quantidade": 200,
              "situacao": "ativo",
              "etapa": "Fila"
            }
          ],
          "criado_em": "2026-10-05T10:00:00-03:00",
          "atualizado_em": "2026-10-05T10:00:00-03:00",
          "finalizado_em": null
        }
      }
    }
  }
}