{"openapi":"3.0.3","info":{"title":"Varejo Hub Platform API","version":"1.0.0","description":"## Construa em cima do e-commerce unificado\n\nA **Varejo Hub Platform API** é uma API REST multi-tenant que dá acesso programático a todo o stack de e-commerce da Varejo Hub - catálogo, pedidos (OMS), checkout, logística, pagamentos, promoções, B2B, busca, clientes, conteúdo e integrações.\n\nOs mesmos endpoints que alimentam o painel do lojista e as lojas virtuais estão disponíveis aqui. Use para construir integrações próprias, automatizar operações ou expor dados em sistemas internos.\n\n---\n\n### Autenticação\n\nToda chamada autenticada usa **JWT Bearer** emitido pelo Supabase Auth do tenant:\n\n```http\nAuthorization: Bearer <jwt-token>\n```\n\nTokens carregam o `account_id` (tenant raiz da conta) e o `role` do usuário (`owner`, `manager`, `broker`, `assistant`, `super_admin`). RLS no Postgres garante isolamento por tenant em todas as queries.\n\nRotas internas servidor-a-servidor usam header `x-internal-key` (security scheme `internalKey`).\n\n---\n\n### Multi-tenant\n\nCada token resolve um `account_id` único (nome legacy da plataforma, equivale a `tenant_id` em SaaS). Todos os recursos retornados são automaticamente escopados ao tenant - não é necessário enviar o id na request.\n\nPara operações cross-tenant (apenas `super_admin`), use o prefixo `/admin/*`.\n\n---\n\n### Convenções\n\n- **Valores monetários** em centavos (`BIGINT`). Divida por 100 para exibir.\n- **Datas** em ISO 8601 com timezone UTC.\n- **Paginação** por `page` (1-based) e `page_size` (default 20, max 100).\n- **Erros de domínio** retornam `422` com `{ code, message }` no body. Ex: `cnpj_invalido`, `pedido_minimo_nao_atingido`.\n- **Erros internos** retornam `500` com `{ error: 'erro_interno' }`.\n- **Idempotência** em rotas `POST` sensíveis via header `Idempotency-Key`.\n\n---\n\n### Rate limit\n\n**200 requisições por minuto** por IP. Header `X-RateLimit-Remaining` indica o saldo. Em estouro: `429 Too Many Requests`.\n\n---\n\n### Webhooks\n\nEventos da plataforma são entregues via webhooks assinados com **HMAC-SHA256** no header `x-rekta-signature`. Configure URLs em `/configuracoes/webhooks`.\n\n---\n\n### Versionamento\n\nSpec OpenAPI 3.0 servida em `/docs/json`. Breaking changes ganham novo `major` (`v2`, `v3`). Aditivos não-breaking são deploys incrementais no `v1`.","contact":{"name":"Varejo Hub","url":"https://varejohub.com.br"}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT Bearer do Supabase Auth. Use o token retornado por `supabase.auth.signInWithPassword()` no header `Authorization: Bearer <token>`."},"internalKey":{"type":"apiKey","in":"header","name":"x-internal-key","description":"Chave interna servidor-a-servidor para rotas operacionais. Configurada via `INTERNAL_API_KEY` no env do serviço chamador."}},"schemas":{}},"paths":{"/ops/status":{"get":{"summary":"Status operacional agregado (Healthboard)","tags":["Plataforma - Observabilidade"],"description":"Visão de plataforma: serviços, infra, circuitos de pagamento, filas, crons, partições, alertas ativos e métricas de negócio. Role: super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ops/insights":{"get":{"summary":"Insights de comércio, tracking/CAPI e tenants (cache 60s)","tags":["Plataforma - Observabilidade"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ops/alertas":{"get":{"summary":"Listar alertas de plataforma","tags":["Plataforma - Observabilidade"],"parameters":[{"schema":{"type":"string","enum":["ativos","todos"],"default":"todos"},"in":"query","name":"status","required":false},{"schema":{"type":"integer","default":100},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ops/metricas":{"get":{"summary":"Séries temporais das métricas de negócio","tags":["Plataforma - Observabilidade"],"parameters":[{"schema":{"type":"integer","default":24},"in":"query","name":"horas","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ops/alertas/{id}/resolver":{"post":{"summary":"Resolver alerta manualmente","tags":["Plataforma - Observabilidade"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/sessao/perfil/renovar":{"post":{"summary":"Renovar o perfil guardado","tags":["Sessão"],"description":"Esquece o perfil guardado de quem chama (troca de loja, onboarding): a próxima requisição lê o perfil no banco.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/imoveis":{"get":{"summary":"Listar imóveis","tags":["Hub Core - Imóveis"],"description":"Retorna imóveis do tenant com paginação, filtros por tipo, finalidade, status, bairro, cidade, faixa de valor, quartos e busca textual. Inclui fotos, portais e proprietário.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":12,"maximum":50},"in":"query","name":"page_size","required":false},{"schema":{"type":"string","default":"created_at"},"in":"query","name":"sort","required":false},{"schema":{"type":"string","enum":["asc","desc"]},"in":"query","name":"direction","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false},{"schema":{"type":"string"},"in":"query","name":"finalidade","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"bairro","required":false},{"schema":{"type":"string"},"in":"query","name":"cidade","required":false},{"schema":{"type":"string"},"in":"query","name":"corretor_id","required":false},{"schema":{"type":"integer"},"in":"query","name":"valor_min","required":false},{"schema":{"type":"integer"},"in":"query","name":"valor_max","required":false},{"schema":{"type":"string"},"in":"query","name":"quartos","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}}}},"post":{"summary":"Criar imóvel","tags":["Hub Core - Imóveis"],"description":"Cadastra novo imóvel com validação Zod. Verifica limites do plano via enforcement. Gera código automático se não informado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"titulo":{"type":"string"},"tipo":{"type":"string"},"finalidade":{"type":"string"},"descricao":{"type":"string"},"cep":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"},"portais":{"type":"array","items":{"type":"string"}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/imoveis/{id}":{"get":{"summary":"Detalhe do imóvel","tags":["Hub Core - Imóveis"],"description":"Retorna dados completos do imóvel com fotos, portais, proprietário e corretor.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar imóvel","tags":["Hub Core - Imóveis"],"description":"Atualização parcial do imóvel via whitelist de campos permitidos. Suporta atualização de portais.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir imóvel","tags":["Hub Core - Imóveis"],"description":"Remove imóvel permanentemente e limpa do índice de busca.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/proprietarios":{"get":{"summary":"Listar proprietários","tags":["Hub Core - Proprietários"],"description":"Retorna todos os proprietários do tenant ordenados por nome.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar proprietário","tags":["Hub Core - Proprietários"],"description":"Cadastra proprietário com detecção automática de tipo (PF/PJ) pelo documento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","documento"],"properties":{"nome":{"type":"string"},"documento":{"type":"string"},"telefone":{"type":"string"},"email":{"type":"string"},"ativo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/proprietarios/{id}":{"patch":{"summary":"Atualizar proprietário","tags":["Hub Core - Proprietários"],"description":"Atualização parcial do proprietário. Recalcula tipo PF/PJ se documento for alterado.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir proprietário","tags":["Hub Core - Proprietários"],"description":"Remove proprietário. Bloqueia se houver imóveis vinculados (409 Conflict).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/contagens":{"get":{"summary":"Contagens das abas do catálogo","tags":["Catálogo - Produtos"],"description":"Quantos produtos cada aba da lista mostra (todos, ativo, rascunho, arquivado), com produtos agrupados contando 1 por grupo como a lista com agrupar=true, e `cadastrados`: os produtos da loja sem agrupar.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"todos":{"type":"integer"},"ativo":{"type":"integer"},"rascunho":{"type":"integer"},"arquivado":{"type":"integer"},"cadastrados":{"type":"integer"}}}}}}}}},"/produtos/metricas":{"get":{"summary":"Métricas de catálogo","tags":["Catálogo - Produtos"],"description":"Retorna sell-through rate, dias de estoque restante, valor de estoque e unidades vendidas no período. Estilo Shopify Analytics.","parameters":[{"schema":{"type":"integer","default":30},"in":"query","name":"periodo","required":false,"description":"Período em dias para cálculo de vendas"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"sell_through_rate":{"type":"number","description":"Taxa de giro em % (ex: 15.25)"},"dias_estoque_restante":{"type":["null","integer"],"description":"Dias até zerar estoque (null se sem vendas)"},"valor_estoque_total":{"type":"integer","description":"Valor total do estoque em centavos"},"periodo_dias":{"type":"integer"},"unidades_vendidas":{"type":"integer"},"estoque_final":{"type":"integer"},"total_produtos":{"type":"integer"},"parcial":{"type":"boolean","description":"true quando o teto de leitura foi atingido e os números são parciais"}}}}}}}}},"/produtos":{"get":{"summary":"Listar produtos","tags":["Catálogo - Produtos"],"description":"Retorna produtos do tenant com filtros, paginação e variações. A busca textual segue o motor da loja (lojas.busca_motor): no clássico, produtos_busca_rank (nome, marca, SKU/GTIN, tags, categoria, descrição, com tolerância a erro de digitação); no novo, o motor único (Typesense com reserva Postgres) com contexto admin. Sem `sort`, ordena por relevância. Se a RPC falhar, cai no ILIKE.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false,"description":"Página"},{"schema":{"type":"integer","default":12},"in":"query","name":"page_size","required":false,"description":"Itens por página (handler limita a 50)"},{"schema":{"type":"string"},"in":"query","name":"search","required":false,"description":"Busca por nome, marca, SKU/GTIN, tags, categoria ou descrição (por relevância)"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"categoria_id","required":false,"description":"Filtrar por categoria"},{"schema":{"type":"string"},"in":"query","name":"categoria","required":false,"description":"Filtrar por nome da categoria"},{"schema":{"type":"string"},"in":"query","name":"subcategoria","required":false,"description":"Filtrar por subcategoria"},{"schema":{"type":"string"},"in":"query","name":"marca","required":false,"description":"Filtrar por marca (parcial)"},{"schema":{"type":"boolean"},"in":"query","name":"destaque","required":false,"description":"Filtrar apenas destaques"},{"schema":{"type":"boolean"},"in":"query","name":"ativo","required":false,"description":"Filtrar por status ativo/inativo (legado)"},{"schema":{"type":"string","enum":["rascunho","ativo","arquivado"]},"in":"query","name":"status","required":false,"description":"Filtrar por status do produto (rascunho/ativo/arquivado)"},{"schema":{"type":"string","enum":["em_estoque","sem_estoque","baixo"]},"in":"query","name":"estoque_status","required":false,"description":"Filtrar por situação de estoque"},{"schema":{"type":"integer"},"in":"query","name":"preco_min","required":false,"description":"Preço mínimo em centavos"},{"schema":{"type":"integer"},"in":"query","name":"preco_max","required":false,"description":"Preço máximo em centavos"},{"schema":{"type":"boolean"},"in":"query","name":"com_promocao","required":false,"description":"true = só com preço promocional; false = só sem"},{"schema":{"type":"boolean"},"in":"query","name":"disponivel_b2c","required":false,"description":"Disponível na loja online"},{"schema":{"type":"boolean"},"in":"query","name":"disponivel_pdv","required":false,"description":"Disponível no PDV"},{"schema":{"type":"string","enum":["ecommerce","catalogo","orcamento","herdado"]},"in":"query","name":"modo_venda","required":false,"description":"App Catálogo e Orçamento: filtra pelo modo GRAVADO no produto. \"herdado\" = sem modo próprio (segue categoria ou padrão da loja)"},{"schema":{"type":"boolean"},"in":"query","name":"assinatura_ativa","required":false,"description":"Com assinatura recorrente"},{"schema":{"type":"string"},"in":"query","name":"tag","required":false,"description":"Filtrar produtos que contêm a tag"},{"schema":{"type":"string","enum":["com","sem"]},"in":"query","name":"tem_imagem","required":false,"description":"Filtrar por presença de imagem (com = ao menos 1 imagem; sem = nenhuma)"},{"schema":{"type":"string","enum":["nome","preco","estoque","created_at","updated_at"]},"in":"query","name":"sort","required":false,"description":"Campo de ordenação"},{"schema":{"type":"string","enum":["asc","desc"]},"in":"query","name":"dir","required":false,"description":"Direção da ordenação"},{"schema":{"type":"boolean"},"in":"query","name":"agrupar","required":false,"description":"Produtos agrupados (tamanhos e cores do mesmo modelo) viram 1 linha, a do membro que representa o grupo, com `grupo` (nome, eixos, membros, contagens por eixo, estoque somado e ids dos membros)."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"},"truncado":{"type":"boolean","description":"Só com busca: a busca casou mais produtos que o teto (5.000) da ação em massa. No clássico a lista cobre os primeiros por relevância; no motor novo, só com busca e aba, o total é o real. Refine o termo ou os filtros."},"motor":{"type":"string","enum":["typesense","postgres"],"description":"Só com busca: o motor que respondeu (lojas.busca_motor; typesense cai no postgres em erro ou demora)."}}}}}}}}}},"post":{"summary":"Criar produto","tags":["Catálogo - Produtos"],"description":"Cria um produto com opções e variações inline. Suporta campos fiscais (NCM, CEST, origem), canais (B2C, PDV), cashback e assinatura recorrente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","description":"Nome do produto"},"descricao":{"type":"string","description":"Descrição do produto"},"sku":{"type":"string","description":"SKU único do produto"},"categoria_id":{"type":["string","null"],"format":"uuid","description":"ID da categoria"},"preco":{"type":["number","null"],"minimum":0,"description":"Preço em centavos"},"preco_promocional":{"type":["number","null"],"description":"Preço promocional em centavos"},"estoque":{"type":"integer","description":"Quantidade em estoque"},"peso_gramas":{"type":["integer","null"],"description":"Peso em gramas"},"largura_cm":{"type":["number","null"],"description":"Largura em cm"},"altura_cm":{"type":["number","null"],"description":"Altura em cm"},"profundidade_cm":{"type":["number","null"],"description":"Profundidade em cm"},"ativo":{"type":"boolean","default":true},"destaque":{"type":"boolean","default":false},"tipo":{"type":"string"},"marca":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}},"cashback_percent":{"type":["number","null"],"minimum":0,"maximum":100,"description":"Percentual de cashback"},"exige_envio":{"type":"boolean","description":"Requer envio físico"},"disponivel_b2c":{"type":"boolean","description":"Disponível na loja online"},"disponivel_pdv":{"type":"boolean","description":"Disponível no PDV"},"modo_venda":{"type":["string","null"],"enum":["ecommerce","catalogo","orcamento",null],"description":"App Catálogo e Orçamento: como o produto é vendido. null = herda da categoria e, na falta, do padrão da loja"},"ncm":{"type":["string","null"],"pattern":"^\\d{8}$","description":"NCM (8 dígitos)"},"cest":{"type":["string","null"],"pattern":"^\\d{7}$","description":"CEST (7 dígitos)"},"origem_fiscal":{"type":["integer","null"],"minimum":0,"maximum":8,"description":"Origem fiscal (0-8)"},"template_slug":{"type":["string","null"],"description":"Template de layout de grupo (product.<slug>); null usa o genérico"},"assinatura_ativa":{"type":"boolean","description":"Ativar assinatura recorrente"},"assinatura_frequencias":{"type":"array","items":{"type":"string"},"description":"Frequências disponíveis"},"assinatura_descontos":{"type":["object","null"],"description":"Descontos por frequência","additionalProperties":true},"controlado_por_lote":{"type":"boolean","description":"Estoque gerido por lotes com validade (FEFO/FIFO)"},"metodo_baixa_lote":{"type":"string","enum":["fefo","fifo"],"description":"fefo = menor validade primeiro; fifo = entrada mais antiga primeiro"},"is_kit":{"type":"boolean","description":"Produto composto (kit VTEX): estoque derivado dos componentes; a baixa expande nos componentes"},"componentes":{"type":"array","description":"Componentes do kit (obrigatório quando is_kit=true)","items":{"type":"object","additionalProperties":true,"properties":{"componente_produto_id":{"type":"string","format":"uuid"},"componente_variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"opcoes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Opções do produto (ex: Cor, Tamanho)"},"variacoes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Variações a criar"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/por-codigo":{"get":{"summary":"Resolver produto por código bipado","tags":["Catálogo - Produtos"],"description":"Resolve produto/variação a partir de um código de barras bipado: GS1 Data Matrix (AIs 01/10/17), GTIN ou SKU exato. Retorna lote_scan/validade_scan quando o GS1 trouxe lote/validade.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":200},"in":"query","name":"codigo","required":true,"description":"Código bipado (GS1 legível/cru, GTIN ou SKU)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/{id}":{"get":{"summary":"Obter produto por ID","tags":["Catálogo - Produtos"],"description":"Retorna produto com todas as relações: imagens, variações, opções (com valores), serviços vinculados, categoria e embalagem.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"patch":{"summary":"Atualizar produto","tags":["Catálogo - Produtos"],"description":"Atualiza campos do produto. Suporta concorrência otimista via updated_at_base - retorna 409 se o registro foi modificado desde a última leitura (ex: editado pela Rê).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"descricao":{"type":"string"},"sku":{"type":"string"},"preco":{"type":["number","null"],"minimum":0},"preco_promocional":{"type":["number","null"]},"estoque":{"type":"integer"},"ativo":{"type":"boolean"},"destaque":{"type":"boolean"},"cashback_percent":{"type":["number","null"],"minimum":0,"maximum":100},"ncm":{"type":["string","null"]},"cest":{"type":["string","null"]},"origem_fiscal":{"type":["integer","null"]},"template_slug":{"type":["string","null"],"description":"Template de layout de grupo (product.<slug>); null usa o genérico"},"controlado_por_lote":{"type":"boolean","description":"Estoque gerido por lotes com validade (FEFO/FIFO)"},"metodo_baixa_lote":{"type":"string","enum":["fefo","fifo"],"description":"fefo = menor validade primeiro; fifo = entrada mais antiga primeiro"},"is_kit":{"type":"boolean","description":"Produto composto (kit VTEX): estoque derivado dos componentes"},"componentes":{"type":"array","description":"Componentes do kit (substitui a composição inteira; obrigatório >=1 quando is_kit=true)","items":{"type":"object","additionalProperties":true,"properties":{"componente_produto_id":{"type":"string","format":"uuid"},"componente_variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"updated_at_base":{"type":"string","format":"date-time","description":"Timestamp da última leitura para controle de concorrência"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizado com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir produto","tags":["Catálogo - Produtos"],"description":"Remove permanentemente um produto e todas as suas relações (imagens, variações, opções, serviços).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluído com sucesso"},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"anuncios":{"type":"array","items":{"type":"string"}}}}}}}}}},"/produtos/{id}/vinculos-erp":{"get":{"summary":"ERPs vinculados a este produto","tags":["Catálogo - Produtos"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/historico":{"get":{"summary":"Histórico de alterações do produto","tags":["Catálogo - Produtos"],"description":"Últimas alterações editoriais da ficha, mais novas primeiro. Retenção de 30 dias. Estoque não entra aqui: tem histórico próprio de movimentações.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/reservas":{"get":{"summary":"Quem está segurando o estoque deste produto","tags":["Catálogo - Produtos"],"description":"Físico, reservado e disponível do produto, mais a lista das reservas VIVAS (ativa/confirmada) com o dono de cada uma. Reserva encerrada não entra.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/historico/{entradaId}/reverter":{"post":{"summary":"Desfazer a alteração de um campo","tags":["Catálogo - Produtos"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["campo"],"properties":{"campo":{"type":"string","description":"Campo a devolver ao valor anterior"}}}}},"required":true},"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"entradaId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/exportar-erp":{"post":{"summary":"Criar este produto no ERP conectado","tags":["Catálogo - Produtos"],"description":"Cria o produto no ERP quando ele ainda não existe lá. Recusa se já houver vínculo ou se o SKU já estiver cadastrado no ERP. Nunca atualiza ficha existente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"integracao_id":{"type":"string","format":"uuid"}}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/opcoes/sync":{"post":{"summary":"Sincronizar opções do produto","tags":["Catálogo - Produtos"],"description":"Substitui todas as opções e valores do produto (delete + recreate). Usado pelo editor de opções.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["opcoes"],"properties":{"opcoes":{"type":"array","items":{"type":"object","properties":{"nome":{"type":"string","description":"Nome da opção (ex: Cor, Tamanho)"},"valores":{"type":"array","items":{"type":"string"},"description":"Valores possíveis"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/duplicar":{"post":{"summary":"Duplicar produto","tags":["Catálogo - Produtos"],"description":"Clona produto com variantes e imagens. O clone nasce como rascunho inativo, com nome prefixado \"Cópia de\" e SKU/slug/GTIN zerados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto original"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid","description":"ID do produto clonado"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/variacoes/gerar":{"post":{"summary":"Gerar variações a partir de opções","tags":["Catálogo - Produtos"],"description":"Substitui variações existentes e gera novas a partir do produto combinatório de opções. Resolve FKs de opcao_valor automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["variacoes"],"properties":{"variacoes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Variações a criar"},"opcoes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Opções associadas (opcional)"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/variacoes/previa-remocao":{"post":{"summary":"Prévia das variações que um salvamento da grade apagaria","tags":["Catálogo - Produtos"],"description":"Não grava nada. Recebe a grade que o editor vai enviar ao /variacoes/gerar e devolve as variações existentes que sairiam, com os kits que as usam como componente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["variacoes"],"properties":{"variacoes":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Grade que seria enviada ao /variacoes/gerar"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/skus-em-uso":{"post":{"summary":"Outros cadastros da loja que já usam os SKUs informados","tags":["Catálogo - Produtos"],"description":"Não grava nada. Compara sem caixa, no SKU do produto e no da variação. O produto informado em produto_id (e as variações dele) fica de fora. Até 3 cadastros por SKU.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["skus"],"properties":{"skus":{"type":"array","maxItems":300,"items":{"type":"string","maxLength":120}},"produto_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/uso-em-kits":{"post":{"summary":"Kits que usam os produtos informados como componente","tags":["Catálogo - Produtos"],"description":"Não grava nada. Kits que também estão entre os produtos informados não entram (saem junto).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_ids"],"properties":{"produto_ids":{"type":"array","maxItems":500,"items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/bulk":{"post":{"summary":"Ações em massa de produtos","tags":["Catálogo - Produtos"],"description":"Aplica uma ação a vários produtos. Alvo por `ids` (seleção explícita) OU por `filtro` (todos que batem o filtro, estilo Shopify \"selecionar todos os N\"). Ações: status, destaque, categoria, tags_add, tags_remove, disponibilidade, preco, preco_promocional, estoque, cashback, duplicar, excluir. Sempre escopado ao tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["action"],"additionalProperties":true,"properties":{"action":{"type":"string","description":"Ação a aplicar"},"ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"IDs explícitos (seleção da tela)"},"filtro":{"type":"object","additionalProperties":true,"description":"Filtros da listagem para alvo cross-page (todos que batem)"},"excluir_ids":{"type":"array","items":{"type":"string","format":"uuid"},"description":"IDs a desconsiderar do alvo quando usar `filtro`"},"valor":{"description":"Parâmetro da ação (varia por ação)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"afetados":{"type":"integer"},"falhas":{"type":"integer"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/produtos/exportar":{"get":{"summary":"Exportar produtos (CSV no formato da Shopify, cabeçalhos em pt-BR)","tags":["Catálogo - Produtos"],"description":"escopo=todos (padrão) | ids (página atual ou selecionados: ids=a,b,c, até 250) | busca (os mesmos filtros da lista na querystring). Devolve cabeçalho e linhas; o painel monta o arquivo.","parameters":[{"schema":{"type":"string","enum":["todos","ids","busca"]},"in":"query","name":"escopo","required":false},{"schema":{"type":"string"},"in":"query","name":"ids","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/importar/previa":{"post":{"summary":"Prévia da importação de produtos","tags":["Catálogo - Produtos"],"description":"Lê a planilha (nosso formato, ou o CSV da Shopify atual ou antigo), casa pelo identificador e, sem ele, pelo SKU, e diz por produto o que seria criado, atualizado, ignorado ou recusado, com os valores que seriam apagados. NÃO grava nada. Só owner e manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["linhas"],"properties":{"linhas":{"type":"array","items":{"type":"array"},"description":"Primeira aba da planilha, linha a linha, cabeçalho incluso."},"primeira_linha":{"type":"integer","minimum":1,"description":"Número, no Excel, da primeira linha enviada. Padrão 1."},"arquivo":{"type":["string","null"],"maxLength":255},"substituir":{"type":"boolean","description":"Substituir produtos com o mesmo identificador (desmarcado: existentes são ignorados)."},"publicar_novos":{"type":"boolean","description":"Produto novo sem coluna Status nasce ativo (desmarcado: rascunho)."}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/importar":{"post":{"summary":"Importar produtos (em segundo plano)","tags":["Catálogo - Produtos"],"description":"Põe a importação na fila e devolve o id. O job refaz o plano da prévia contra o catálogo do momento e grava em lotes. Uma importação por loja de cada vez. Só owner e manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["linhas"],"properties":{"linhas":{"type":"array","items":{"type":"array"},"description":"Primeira aba da planilha, linha a linha, cabeçalho incluso."},"primeira_linha":{"type":"integer","minimum":1,"description":"Número, no Excel, da primeira linha enviada. Padrão 1."},"arquivo":{"type":["string","null"],"maxLength":255},"substituir":{"type":"boolean","description":"Substituir produtos com o mesmo identificador (desmarcado: existentes são ignorados)."},"publicar_novos":{"type":"boolean","description":"Produto novo sem coluna Status nasce ativo (desmarcado: rascunho)."}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/importar/atual":{"get":{"summary":"Última importação de produtos da loja","tags":["Catálogo - Produtos"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produtos/importar/{id}":{"get":{"summary":"Andamento e relatório de uma importação de produtos","tags":["Catálogo - Produtos"],"parameters":[{"schema":{"type":"string","maxLength":120},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/produto-grupos/do-produto/{produtoId}":{"get":{"summary":"Grupo do produto","tags":["Catálogo - Produtos agrupados"],"description":"Devolve o grupo em que o produto está, ou `grupo: null`.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupo":{"anyOf":[{"type":"object","required":["id","nome","eixos","origem","membros"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["manual","sugestao"]},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"slug":{"type":["null","string"]},"sku":{"type":["null","string"]},"ativo":{"type":"boolean"},"imagem":{"type":["null","string"]},"preco_centavos":{"type":"integer"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"posicao":{"type":"integer"}}}}}},{"type":"null"}]}}}}}}}}},"/produto-grupos/{id}":{"get":{"summary":"Detalhe do grupo","tags":["Catálogo - Produtos agrupados"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupo":{"type":"object","required":["id","nome","eixos","origem","membros"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["manual","sugestao"]},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"slug":{"type":["null","string"]},"sku":{"type":["null","string"]},"ativo":{"type":"boolean"},"imagem":{"type":["null","string"]},"preco_centavos":{"type":"integer"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"posicao":{"type":"integer"}}}}}}}}}}}}},"patch":{"summary":"Editar grupo de produtos","tags":["Catálogo - Produtos agrupados"],"description":"Altera nome, eixos e membros. Quando vem `membros`, eles substituem o conjunto, na ordem do array.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"membros":{"type":"array","items":{"type":"object","required":["produto_id","valores"],"properties":{"produto_id":{"type":"string"},"valores":{"type":"object"}}}},"mover":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupo":{"type":"object","required":["id","nome","eixos","origem","membros"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["manual","sugestao"]},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"slug":{"type":["null","string"]},"sku":{"type":["null","string"]},"ativo":{"type":"boolean"},"imagem":{"type":["null","string"]},"preco_centavos":{"type":"integer"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"posicao":{"type":"integer"}}}}}}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"produtos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"grupo_id":{"type":"string"},"grupo_nome":{"type":"string"}}}}}}}}}}},"delete":{"summary":"Desfazer grupo de produtos","tags":["Catálogo - Produtos agrupados"],"description":"Apaga o grupo e os vínculos. Os produtos não mudam.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"produtos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"grupo_id":{"type":"string"},"grupo_nome":{"type":"string"}}}}}}}}}}}},"/produto-grupos/inferir":{"post":{"summary":"Inferir grupo pelos nomes","tags":["Catálogo - Produtos agrupados"],"description":"Lê os nomes dos produtos e propõe nome, eixos e valores para o diálogo Agrupar. Não grava nada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_ids"],"properties":{"produto_ids":{"type":"array","items":{"type":"string"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"valores":{"type":"object","additionalProperties":{"type":"string"}}}}},"confianca":{"type":"string","enum":["alta","baixa"]}}}}}}}}},"/produto-grupos/automatico":{"post":{"summary":"Agrupar tamanhos e cores automaticamente","tags":["Catálogo - Produtos agrupados"],"description":"Lê o nome de cada produto (como o ERP cadastrou: \"TAM P\", \"TAM M\", \"COR PRETO\") e junta em grupo os cadastros do mesmo modelo. Sem `aplicar`, só devolve a prévia. Grupos montados à mão não mudam de eixo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"aplicar":{"type":"boolean"},"grupos":{"type":"array","items":{"type":"string"},"description":"Com `aplicar`, só os grupos destas chaves (as da prévia). Sem a lista, todos."}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupos":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"tipo":{"type":"string","enum":["novo","inclusao"]},"grupo_id":{"type":["null","string"]},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"ativo":{"type":"boolean"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"novo":{"type":"boolean"}}}}}}},"total_grupos":{"type":"integer"},"total_produtos":{"type":"integer"},"aplicado":{"type":"boolean"},"gravados":{"type":"integer"},"produtos_agrupados":{"type":"integer"},"falhas":{"type":"array","items":{"type":"object","properties":{"grupo":{"type":"string"},"motivo":{"type":"string"}}}}}}}}}}}},"/produto-grupos":{"post":{"summary":"Criar grupo de produtos","tags":["Catálogo - Produtos agrupados"],"description":"Agrupa de 2 a 60 produtos da loja. Produto já em outro grupo devolve 409, a menos que venha `mover: true`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","eixos","membros"],"properties":{"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"membros":{"type":"array","items":{"type":"object","required":["produto_id","valores"],"properties":{"produto_id":{"type":"string"},"valores":{"type":"object"}}}},"mover":{"type":"boolean"},"origem":{"type":"string","enum":["manual","sugestao"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupo":{"type":"object","required":["id","nome","eixos","origem","membros"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["manual","sugestao"]},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"slug":{"type":["null","string"]},"sku":{"type":["null","string"]},"ativo":{"type":"boolean"},"imagem":{"type":["null","string"]},"preco_centavos":{"type":"integer"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"posicao":{"type":"integer"}}}}}}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"produtos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"grupo_id":{"type":"string"},"grupo_nome":{"type":"string"}}}}}}}}}}}},"/produto-grupos/{id}/membros/{produtoId}":{"delete":{"summary":"Tirar produto do grupo","tags":["Catálogo - Produtos agrupados"],"description":"Tira o produto do grupo. Se sobrar 1 membro, o grupo é desfeito e a resposta vem com `grupo: null`.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"grupo":{"anyOf":[{"type":"object","required":["id","nome","eixos","origem","membros"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"eixos":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["manual","sugestao"]},"membros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"slug":{"type":["null","string"]},"sku":{"type":["null","string"]},"ativo":{"type":"boolean"},"imagem":{"type":["null","string"]},"preco_centavos":{"type":"integer"},"valores":{"type":"object","additionalProperties":{"type":"string"}},"posicao":{"type":"integer"}}}}}},{"type":"null"}]}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"},"produtos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"grupo_id":{"type":"string"},"grupo_nome":{"type":"string"}}}}}}}}}}}},"/combos":{"get":{"summary":"Listar todos os combos do tenant","tags":["Catálogo - Combos (Compre Junto)"],"description":"Retorna todos os combos (Compre Junto) do tenant com produto gatilho, itens complementares e configuração de desconto. Uso administrativo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/produtos/{id}/combos":{"get":{"summary":"Listar combos de um produto","tags":["Catálogo - Combos (Compre Junto)"],"description":"Retorna combos ativos de um produto, filtrados por vigência e limite de uso. Máximo 5 combos, ordenados por prioridade. Rota pública (storefront) ou autenticada.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false,"description":"ID do tenant (acesso público)"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto gatilho"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar combo (Compre Junto)","tags":["Catálogo - Combos (Compre Junto)"],"description":"Cria um combo vinculado a um produto gatilho. Suporta desconto por item, vigência, limite de usos e prioridade (0-100).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["itens"],"properties":{"nome":{"type":"string","default":"Compre Junto","description":"Nome do combo"},"desconto_tipo":{"type":"string","enum":["percentual","fixo"],"default":"percentual"},"desconto_valor":{"type":"number","default":5,"description":"Valor do desconto"},"prioridade":{"type":"integer","minimum":0,"maximum":100,"default":0},"vigencia_inicio":{"type":["string","null"],"description":"Início da vigência (date ou date-time)"},"vigencia_fim":{"type":["string","null"],"description":"Fim da vigência (date ou date-time)"},"limite_usos_total":{"type":["integer","null"],"description":"Limite total de usos"},"limite_usos_por_cliente":{"type":["integer","null"],"description":"Limite de usos por cliente"},"itens":{"type":"array","minItems":1,"maxItems":5,"items":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","format":"uuid","description":"ID do produto complementar"},"desconto_tipo":{"type":["string","null"],"enum":["percentual","fixo",null]},"desconto_valor":{"type":["number","null"]}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto gatilho"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/combos/{comboId}":{"patch":{"summary":"Atualizar combo","tags":["Catálogo - Combos (Compre Junto)"],"description":"Atualiza configuração do combo. Se itens forem fornecidos, substitui todos os itens existentes (delete + recreate).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"desconto_tipo":{"type":"string","enum":["percentual","fixo"]},"desconto_valor":{"type":"number"},"ativo":{"type":"boolean"},"prioridade":{"type":"integer","minimum":0,"maximum":100},"vigencia_inicio":{"type":["string","null"]},"vigencia_fim":{"type":["string","null"]},"limite_usos_total":{"type":["integer","null"]},"limite_usos_por_cliente":{"type":["integer","null"]},"itens":{"type":"array","maxItems":5,"items":{"type":"object","additionalProperties":true}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"comboId","required":true,"description":"ID do combo"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizado com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir combo","tags":["Catálogo - Combos (Compre Junto)"],"description":"Remove permanentemente um combo e seus itens associados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"comboId","required":true,"description":"ID do combo"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluído com sucesso"}}}},"/produtos/combos/{comboId}/uso":{"post":{"summary":"Incrementar uso do combo","tags":["Catálogo - Combos (Compre Junto)"],"description":"Incrementa o contador usos_total do combo. Chamado internamente pelo checkout após confirmação de pagamento.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"comboId","required":true,"description":"ID do combo"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/servicos":{"get":{"summary":"Listar serviços","tags":["Hub Core - Serviços"],"description":"Retorna serviços do tenant com busca textual e filtro por ativo.","parameters":[{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar serviço","tags":["Hub Core - Serviços"],"description":"Cadastra novo serviço do tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/servicos/{id}":{"get":{"summary":"Detalhe do serviço","tags":["Hub Core - Serviços"],"description":"Retorna dados completos de um serviço.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar serviço","tags":["Hub Core - Serviços"],"description":"Atualização parcial de um serviço.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir serviço","tags":["Hub Core - Serviços"],"description":"Remove serviço permanentemente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/agendamentos":{"get":{"summary":"Listar agendamentos","tags":["Hub Core - Agendamentos"],"description":"Retorna agendamentos com paginação e filtros por status, serviço, intervalo de datas e busca por nome/telefone.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20},"in":"query","name":"page_size","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"servico_id","required":false},{"schema":{"type":"string"},"in":"query","name":"data_inicio","required":false},{"schema":{"type":"string"},"in":"query","name":"data_fim","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar agendamento","tags":["Hub Core - Agendamentos"],"description":"Cria agendamento. Se servico_id informado, preenche duracao_min automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamentos/{id}":{"get":{"summary":"Detalhe do agendamento","tags":["Hub Core - Agendamentos"],"description":"Retorna dados do agendamento com serviço vinculado.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar agendamento","tags":["Hub Core - Agendamentos"],"description":"Atualização parcial do agendamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir agendamento","tags":["Hub Core - Agendamentos"],"description":"Remove agendamento permanentemente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/categorias":{"get":{"summary":"Listar categorias (árvore)","tags":["Catálogo - Categorias"],"description":"Retorna todas as categorias do tenant em estrutura hierárquica (árvore com children). Ordenadas por ordem e nome.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"post":{"summary":"Criar categoria","tags":["Catálogo - Categorias"],"description":"Cria uma nova categoria de produto. Slug é gerado automaticamente a partir do nome se não fornecido. Suporta hierarquia via parent_id.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","description":"Nome da categoria"},"slug":{"type":"string","description":"Slug (auto-gerado se não informado)"},"parent_id":{"type":["string","null"],"format":"uuid","description":"ID da categoria pai (null para raiz)"},"icone":{"type":["string","null"],"description":"Ícone da categoria"},"ordem":{"type":"integer","description":"Posição de ordenação (padrão: depois da última irmã)"},"modo_venda":{"type":["string","null"],"enum":["ecommerce","catalogo","orcamento",null],"description":"App Catálogo e Orçamento: modo padrão dos produtos da categoria. null = herda da categoria pai e, na falta, do padrão da loja"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/categorias/tree":{"get":{"summary":"Árvore de categorias com contagem","tags":["Catálogo - Categorias"],"description":"Retorna árvore de categorias (pais + filhas) com contagem de produtos ativos por categoria. Ideal para sidebar de navegação.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"categorias":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"slug":{"type":"string"},"parent_id":{"type":["null","string"]},"qtd_produtos":{"type":"integer"},"filhas":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}}}}},"/categorias/{id}":{"get":{"summary":"Obter categoria por ID","tags":["Catálogo - Categorias"],"description":"Retorna detalhes da categoria com contagem de produtos vinculados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da categoria"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"patch":{"summary":"Atualizar categoria","tags":["Catálogo - Categorias"],"description":"Atualiza campos da categoria. Se o slug mudar, o slug antigo é preservado em slug_redirect_from para redirecionamento SEO.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"slug":{"type":"string"},"parent_id":{"type":["string","null"]},"icone":{"type":["string","null"]},"ordem":{"type":"integer"},"ativo":{"type":"boolean"},"imagem_url":{"type":["string","null"]},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]},"og_image_url":{"type":["string","null"]},"modo_venda":{"type":["string","null"],"enum":["ecommerce","catalogo","orcamento",null],"description":"App Catálogo e Orçamento: modo padrão dos produtos da categoria. null = herdar"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da categoria"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizada com sucesso"}}},"delete":{"summary":"Excluir categoria","tags":["Catálogo - Categorias"],"description":"Remove uma categoria. Os produtos vão para `mover_produtos_para` (obrigatório se houver produtos; 409 sem ele) e as subcategorias sobem um nível.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"mover_produtos_para","required":false,"description":"Categoria que recebe os produtos da excluída"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da categoria"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluída com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"produtos":{"type":"integer"}}}}}}}}},"/categorias/reorder":{"post":{"summary":"Reordenar categorias","tags":["Catálogo - Categorias"],"description":"Atualiza a ordem de exibição de múltiplas categorias em batch. Verifica pertencimento ao tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","ordem"],"properties":{"id":{"type":"string","format":"uuid"},"ordem":{"type":"integer"}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Reordenadas com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/categorias/reorganizar":{"post":{"summary":"Reorganizar categorias em massa","tags":["Catálogo - Categorias"],"description":"Operação atômica: cria categorias destino (se não existirem), move produtos e opcionalmente limpa categorias vazias. Processa em batches de 80 IDs.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["mapeamento"],"properties":{"mapeamento":{"type":"array","items":{"type":"object","required":["produto_ids","categoria_destino_nome"],"properties":{"produto_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"categoria_destino_nome":{"type":"string","description":"Nome da categoria destino (criada se inexistente)"},"categoria_destino_parent_id":{"type":"string","format":"uuid","description":"Pai da categoria destino"}}}},"limpar_vazias":{"type":"boolean","default":false,"description":"Excluir categorias vazias após reorganização"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"criadas":{"type":"array","items":{"type":"string"}},"movidos":{"type":"integer"},"deletadas":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/conteudo/artigos":{"get":{"summary":"Listar artigos","tags":["Conteúdo"],"description":"Lista paginada dos artigos do tenant. Filtros por status, blog, categoria, autor e busca textual.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"rascunho | em_revisao | agendado | publicado | arquivado"},{"schema":{"type":"string"},"in":"query","name":"blog_slug","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"categoria_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"autor_id","required":false},{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Busca em título, resumo e corpo"},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}}}},"post":{"summary":"Criar artigo","tags":["Conteúdo"],"description":"Cria em rascunho. Publicar é POST /conteudo/artigos/:id/publicar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["titulo"],"properties":{"titulo":{"type":"string","minLength":1},"slug":{"type":"string","description":"Opcional — derivado do título quando ausente"},"blog_slug":{"type":"string","default":"blog"},"resumo":{"type":"string"},"corpo_json":{"type":"object","additionalProperties":true},"capa_url":{"type":"string"},"capa_alt":{"type":"string"},"autor_id":{"type":"string","format":"uuid"},"categoria_id":{"type":"string","format":"uuid"},"tags":{"type":"array","items":{"type":"string"}},"seo_titulo":{"type":"string"},"seo_descricao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/artigos/{id}":{"get":{"summary":"Detalhe do artigo","tags":["Conteúdo"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar artigo","tags":["Conteúdo"],"description":"Não publica: `status` aceita apenas rascunho, em_revisao e arquivado. Trocar o slug de um artigo já publicado cria o 301 automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir artigo","tags":["Conteúdo"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/artigos/{id}/publicar":{"post":{"summary":"Publicar ou agendar artigo","tags":["Conteúdo"],"description":"Sem `publicar_em`, vai ao ar agora. Com `publicar_em` no futuro, fica agendado. `publicado_em` é carimbado pelo servidor e preservado em republicações — é a data que o Google já indexou.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"publicar_em":{"type":"string","format":"date-time","description":"Futuro = agenda; ausente = agora"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/artigos/{id}/despublicar":{"post":{"summary":"Tirar artigo do ar","tags":["Conteúdo"],"description":"Volta para rascunho. `publicado_em` é PRESERVADO — republicar mantém a data que o Google indexou.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/autores":{"get":{"summary":"Listar autores","tags":["Conteúdo"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar autor","tags":["Conteúdo"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1},"bio":{"type":"string"},"avatar_url":{"type":"string"},"redes":{"type":"object","additionalProperties":true},"profile_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/autores/{id}":{"patch":{"summary":"Atualizar autor","tags":["Conteúdo"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir autor","tags":["Conteúdo"],"description":"O artigo NÃO some junto: autor_id vira NULL (ON DELETE SET NULL).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/categorias":{"get":{"summary":"Listar categorias de conteúdo","tags":["Conteúdo"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar categoria de conteúdo","tags":["Conteúdo"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1},"descricao":{"type":"string"},"ordem":{"type":"integer","default":0},"seo_titulo":{"type":"string"},"seo_descricao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/conteudo/categorias/{id}":{"patch":{"summary":"Atualizar categoria de conteúdo","tags":["Conteúdo"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir categoria de conteúdo","tags":["Conteúdo"],"description":"O artigo NÃO some junto: categoria_id vira NULL (ON DELETE SET NULL).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects":{"get":{"summary":"Listar regras de redirecionamento","tags":["Redirects"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Busca em origem e destino"},{"schema":{"type":"string"},"in":"query","name":"metodo","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo_origem","required":false,"description":"exata | padrao"},{"schema":{"type":"string"},"in":"query","name":"ativo","required":false,"description":"true | false"},{"schema":{"type":"string"},"in":"query","name":"com_hits","required":false,"description":"1 = só as que já redirecionaram alguém"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"lote_id","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar regra (uma ou em lote)","tags":["Redirects"],"description":"Uma regra no corpo, ou `regras: []` para lote. Lote grava em blocos de 500 e nasce com `lote_id` para poder ser desfeito.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/{id}":{"patch":{"summary":"Atualizar regra","tags":["Redirects"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Apagar regra","tags":["Redirects"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/validar":{"post":{"summary":"Conferir uma regra sem gravar","tags":["Redirects"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/testar":{"post":{"summary":"Simular um caminho contra as regras ativas","tags":["Redirects"],"description":"Mesma precedência da borda: exata ganha de padrão, padrão mais específico ganha do mais curto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"caminho":{"type":"string"}},"required":["caminho"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/importar/sitemap":{"post":{"summary":"Importar do sitemap da loja antiga","tags":["Redirects"],"description":"Devolve prévia por padrão. Só grava com `aplicar: true`. Segue sitemapindex aninhado, aceita `&amp;` escapado e XML em ISO-8859-1.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"aplicar":{"type":"boolean","default":false},"usar_padrao":{"type":"boolean","default":false,"description":"Grava as regras de padrão sugeridas no lugar das exatas do grupo"}},"required":["url"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/importar/csv":{"post":{"summary":"Importar de CSV de/para","tags":["Redirects"],"description":"Duas colunas, com ou sem cabeçalho. Aceita URL absoluta na origem e extrai o caminho.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"csv":{"type":"string"},"aplicar":{"type":"boolean","default":false}},"required":["csv"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/lotes":{"get":{"summary":"Listar lotes de importação","tags":["Redirects"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/lotes/{id}/desfazer":{"post":{"summary":"Desfazer um lote de importação","tags":["Redirects"],"description":"Apaga as regras do lote. A regra editada à mão depois da importação fica de pé.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/404":{"get":{"summary":"URLs que estão dando 404, por volume","tags":["Redirects"],"description":"Sem isto o cadastro é cego: o lojista adivinha o que redirecionar em vez de consertar o que está sendo acessado.","parameters":[{"schema":{"type":"string"},"in":"query","name":"host","required":false},{"schema":{"type":"string"},"in":"query","name":"incluir_bot","required":false},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/redirects/404/{id}/resolver":{"post":{"summary":"Criar a regra que resolve um 404 do radar","tags":["Redirects"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"para":{"type":"string"}},"required":["para"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/dominios-aposentados":{"get":{"summary":"Listar domínios aposentados","tags":["Redirects"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Apontar um domínio antigo para o Hub só para devolver 301","tags":["Redirects"],"description":"Provisiona o host de verdade (borda e roteamento) antes de gravar. A resposta traz `registros_dns` com a instrução que o lojista precisa aplicar no provedor dele, mais `ssl_status`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string"},"destino_host":{"type":"string"},"fallback":{"type":"string","description":"home | 404 | 410"}},"required":["host"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/dominios-aposentados/{id}":{"patch":{"summary":"Atualizar domínio aposentado","tags":["Redirects"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover domínio aposentado","tags":["Redirects"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/produtos/{id}/imagens":{"get":{"summary":"Listar imagens do produto","tags":["Catálogo - Imagens"],"description":"Retorna todas as imagens de um produto, ordenadas por campo ordem.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"post":{"summary":"Adicionar imagem ao produto","tags":["Catálogo - Imagens"],"description":"Adiciona uma imagem ao produto. Se is_capa=true, desmarca a capa atual. A ordem é calculada automaticamente (próximo valor).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri","description":"URL da imagem"},"alt_text":{"type":["string","null"],"description":"Texto alternativo (SEO)"},"is_capa":{"type":"boolean","default":false,"description":"Definir como imagem de capa"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/imagens/{imagemId}":{"patch":{"summary":"Atualizar imagem do produto","tags":["Catálogo - Imagens"],"description":"Atualiza propriedades de uma imagem (URL, alt_text, is_capa, ordem). Se is_capa=true, desmarca a capa anterior.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"alt_text":{"type":["string","null"]},"is_capa":{"type":"boolean"},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"imagemId","required":true,"description":"ID da imagem"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizada com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Remover imagem do produto","tags":["Catálogo - Imagens"],"description":"Remove permanentemente uma imagem do produto.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"imagemId","required":true,"description":"ID da imagem"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removida com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/imagens/reordenar":{"post":{"summary":"Reordenar imagens do produto","tags":["Catálogo - Imagens"],"description":"Atualiza a ordem de exibição das imagens do produto via drag-and-drop.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["imagens"],"properties":{"imagens":{"type":"array","items":{"type":"object","required":["id","ordem"],"properties":{"id":{"type":"string","format":"uuid","description":"ID da imagem"},"ordem":{"type":"integer","description":"Nova posição"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Reordenadas com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/arquivos":{"get":{"summary":"Listar arquivos (anexos) do produto","tags":["Catálogo - Arquivos"],"description":"Retorna todos os anexos do produto ordenados por campo ordem. Anexos = manuais, certificados, fichas técnicas — exibidos como downloads no PDP.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"post":{"summary":"Adicionar arquivo ao produto","tags":["Catálogo - Arquivos"],"description":"Cria registro de anexo após o upload no bucket. A ordem é calculada automaticamente (próximo valor).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url","nome_arquivo","mime_type","tamanho_bytes"],"properties":{"url":{"type":"string","format":"uri","description":"URL pública do arquivo"},"nome_arquivo":{"type":"string","description":"Nome original do arquivo"},"rotulo":{"type":["string","null"],"description":"Rótulo amigável (opcional)"},"mime_type":{"type":"string","description":"MIME type"},"tamanho_bytes":{"type":"integer","description":"Tamanho em bytes"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/arquivos/{arquivoId}":{"patch":{"summary":"Atualizar arquivo do produto","tags":["Catálogo - Arquivos"],"description":"Atualiza rótulo ou ordem do anexo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rotulo":{"type":["string","null"]},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"arquivoId","required":true,"description":"ID do arquivo"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizado com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Remover arquivo do produto","tags":["Catálogo - Arquivos"],"description":"Remove o registro do banco e o objeto do bucket Storage.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"arquivoId","required":true,"description":"ID do arquivo"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removido com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/arquivos/reordenar":{"post":{"summary":"Reordenar arquivos do produto","tags":["Catálogo - Arquivos"],"description":"Atualiza a ordem de exibição dos anexos via drag-and-drop.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["arquivos"],"properties":{"arquivos":{"type":"array","items":{"type":"object","required":["id","ordem"],"properties":{"id":{"type":"string","format":"uuid"},"ordem":{"type":"integer"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/variacoes":{"get":{"summary":"Listar variações do produto","tags":["Catálogo - Variações"],"description":"Retorna todas as variações (SKUs) de um produto, ordenadas por data de criação.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"post":{"summary":"Criar variação","tags":["Catálogo - Variações"],"description":"Cria uma nova variação (SKU) para o produto. Suporta GTIN, dimensões físicas e preço individual.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","tipo"],"properties":{"nome":{"type":"string","description":"Nome da variação (ex: P / Preto)"},"tipo":{"type":"string","description":"Tipo da variação (ex: Cor, Tamanho)"},"sku":{"type":["string","null"],"description":"SKU único"},"gtin":{"type":["string","null"],"description":"GTIN/EAN (8, 12-14 dígitos)"},"preco":{"type":["number","null"],"description":"Preço em centavos"},"preco_promocional":{"type":["number","null"],"description":"Preço promocional em centavos"},"estoque":{"type":["integer","null"],"description":"Estoque da variação"},"peso_gramas":{"type":["integer","null"],"description":"Peso em gramas"},"largura_cm":{"type":["number","null"]},"altura_cm":{"type":["number","null"]},"profundidade_cm":{"type":["number","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/variacoes/{varId}":{"patch":{"summary":"Atualizar variação","tags":["Catálogo - Variações"],"description":"Atualiza campos de uma variação específica do produto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"sku":{"type":["string","null"]},"gtin":{"type":["string","null"]},"preco":{"type":["number","null"]},"preco_promocional":{"type":["number","null"]},"estoque":{"type":["integer","null"]},"peso_gramas":{"type":["integer","null"]},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"varId","required":true,"description":"ID da variação"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizada com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir variação","tags":["Catálogo - Variações"],"description":"Remove permanentemente uma variação do produto.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"varId","required":true,"description":"ID da variação"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluída com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"anuncios":{"type":"array","items":{"type":"string"}}}}}}}}}},"/produtos/{id}/servicos":{"get":{"summary":"Listar serviços vinculados ao produto","tags":["Catálogo - Serviços"],"description":"Retorna os serviços add-on vinculados ao produto (ex: montagem, garantia estendida) com detalhes completos do serviço.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"post":{"summary":"Vincular serviço ao produto","tags":["Catálogo - Serviços"],"description":"Associa um serviço existente ao produto. Verifica duplicidade e pertencimento ao mesmo tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["servico_id"],"properties":{"servico_id":{"type":"string","format":"uuid","description":"ID do serviço a vincular"},"obrigatorio":{"type":"boolean","default":false,"description":"Se o serviço é obrigatório na compra"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/produtos/{id}/servicos/{vinculoId}":{"delete":{"summary":"Desvincular serviço do produto","tags":["Catálogo - Serviços"],"description":"Remove o vínculo entre um serviço e o produto (não exclui o serviço em si).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do produto"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"vinculoId","required":true,"description":"ID do vínculo produto-serviço"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Desvinculado com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/marcas":{"get":{"summary":"Listar marcas","tags":["Catálogo - Marcas"],"description":"Nomes de marca do tenant: união do registro ativo com os valores distintos de produtos.marca. Ordenados alfabeticamente em pt-BR.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}}}}}}}},"post":{"summary":"Criar marca","tags":["Catálogo - Marcas"],"description":"Cadastra uma marca do tenant. O slug é derivado do nome quando não informado, com desempate por sufixo numérico. Nome repetido (ignorando caixa) devolve 409.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","description":"Nome da marca, como aparece em produtos.marca"},"slug":{"type":"string","description":"Slug (derivado do nome se não informado)"},"logo_url":{"type":["string","null"]},"descricao":{"type":["string","null"]},"site_url":{"type":["string","null"]},"destaque":{"type":"boolean","default":false},"ativo":{"type":"boolean","default":true},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"slug":{"type":"string"},"logo_url":{"type":["null","string"]},"descricao":{"type":["null","string"]},"site_url":{"type":["null","string"]},"ordem":{"type":"integer"},"destaque":{"type":"boolean"},"ativo":{"type":"boolean"},"produtos_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/marcas/registro":{"get":{"summary":"Registro de marcas","tags":["Catálogo - Marcas"],"description":"Marcas cadastradas do tenant com contagem de produtos que usam o nome, mais os nomes presentes em produtos.marca que ainda não têm registro (pendentes).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"slug":{"type":"string"},"logo_url":{"type":["null","string"]},"descricao":{"type":["null","string"]},"site_url":{"type":["null","string"]},"ordem":{"type":"integer"},"destaque":{"type":"boolean"},"ativo":{"type":"boolean"},"produtos_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}},"pendentes":{"type":"array","items":{"type":"string"}}}}}}}}}},"/marcas/reordenar":{"patch":{"summary":"Reordenar marcas","tags":["Catálogo - Marcas"],"description":"Grava o campo ordem pela posição de cada id no array. Recusa id que não seja do tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Reordenadas com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/marcas/sincronizar":{"post":{"summary":"Sincronizar marcas pendentes","tags":["Catálogo - Marcas"],"description":"Cria registro para cada nome que aparece em produtos.marca e ainda não tem marca cadastrada.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"criadas":{"type":"integer"}}}}}}}}},"/marcas/{id}":{"patch":{"summary":"Atualizar marca","tags":["Catálogo - Marcas"],"description":"Atualiza campos da marca. Se o nome mudar, os produtos do tenant que usam o nome antigo são renomeados ANTES da gravação do registro, senão o registro descola do catálogo e o filtro da vitrine passa a mostrar as duas grafias. Não há transação entre as duas escritas: falha na propagação devolve 500 com o registro intacto, e o mesmo PATCH pode ser repetido.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"slug":{"type":"string"},"logo_url":{"type":["string","null"]},"descricao":{"type":["string","null"]},"site_url":{"type":["string","null"]},"destaque":{"type":"boolean"},"ativo":{"type":"boolean"},"meta_title":{"type":["string","null"]},"meta_description":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da marca"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"slug":{"type":"string"},"logo_url":{"type":["null","string"]},"descricao":{"type":["null","string"]},"site_url":{"type":["null","string"]},"ordem":{"type":"integer"},"destaque":{"type":"boolean"},"ativo":{"type":"boolean"},"produtos_count":{"type":"integer"},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"produtos_atualizados":{"type":"integer"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir marca","tags":["Catálogo - Marcas"],"description":"Remove o registro da marca. Não apaga nem limpa produtos.marca: o produto continua com a marca escrita, só perde logo, descrição e ordem.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da marca"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluída com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/embalagens":{"get":{"summary":"Listar embalagens","tags":["Catálogo - Embalagens"],"description":"Retorna embalagens cadastradas do tenant, ordenadas por nome. Usadas para cálculo de frete.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"post":{"summary":"Criar embalagem","tags":["Catálogo - Embalagens"],"description":"Cadastra uma nova embalagem com dimensões e peso para cálculo de frete.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","description":"Nome da embalagem (ex: Caixa Média)"},"largura_cm":{"type":["number","null"],"description":"Largura em cm"},"altura_cm":{"type":["number","null"],"description":"Altura em cm"},"profundidade_cm":{"type":["number","null"],"description":"Profundidade em cm"},"peso_gramas":{"type":["integer","null"],"description":"Peso em gramas"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/embalagens/{id}":{"patch":{"summary":"Atualizar embalagem","tags":["Catálogo - Embalagens"],"description":"Atualiza campos de uma embalagem existente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"largura_cm":{"type":["number","null"]},"altura_cm":{"type":["number","null"]},"profundidade_cm":{"type":["number","null"]},"peso_gramas":{"type":["integer","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da embalagem"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizada com sucesso"}}},"delete":{"summary":"Excluir embalagem","tags":["Catálogo - Embalagens"],"description":"Remove permanentemente uma embalagem.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da embalagem"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluída com sucesso"}}}},"/leads-institucionais":{"get":{"summary":"Listar leads do site institucional","tags":["Admin - Backoffice"],"description":"Listagem paginada dos leads capturados no site (formulário /contato, CTAs /planos, chat Ana). Filtro opcional por status. Requer super_admin.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":30},"in":"query","name":"limit","required":false},{"schema":{"type":"string","enum":["novo","contatado","convertido","descartado"]},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"total_pages":{"type":"integer"},"novos":{"type":"integer"}}}}}}}}}}},"/leads-institucionais/{id}":{"patch":{"summary":"Atualizar status do lead institucional","tags":["Admin - Backoffice"],"description":"Move o lead no funil (novo → contatado → convertido/descartado). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["novo","contatado","convertido","descartado"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/stats":{"get":{"summary":"Visão geral do backoffice","tags":["Admin - Backoffice"],"description":"Retorna total de tenants, distribuição por plano e cadastros recentes (últimos 7 dias). Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"total_tenants":{"type":"integer"},"by_plan":{"type":"object","additionalProperties":true},"recent":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/tenants":{"get":{"summary":"Listar tenants","tags":["Admin - Backoffice"],"description":"Listagem paginada de tenants com filtros por busca, plano e status ativo. Requer super_admin.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false},{"schema":{"type":"string"},"in":"query","name":"plano","required":false},{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}}}},"post":{"summary":"Criar tenant","tags":["Admin - Backoffice"],"description":"Cria novo tenant (imobiliária). Valida unicidade do slug. `privada: true` cria a loja já privada, visível só para quem criou (exige a área plataforma). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","slug"],"properties":{"nome":{"type":"string"},"slug":{"type":"string"},"segmento":{"type":"string","default":"imobiliaria"},"plano":{"type":"string","default":"essencial"},"modulos_ativos":{"type":"array","items":{"type":"string"}},"privada":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tenants/{id}":{"get":{"summary":"Detalhe do tenant","tags":["Admin - Backoffice"],"description":"Retorna dados completos do tenant com contagens de profiles, imóveis, leads e produtos. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar tenant","tags":["Admin - Backoffice"],"description":"Atualização parcial de tenant. Campos permitidos: nome, slug, plano, segmento, modulos_ativos, features_extras, ativo. Trocar `plano` altera a assinatura (assinaturas.plano_id, fonte de verdade do gate de features) e espelha a coluna — recusado para tenant sem assinatura ou com cobrança ativa no Asaas, que têm caminho próprio no billing. `features_extras` só aceita keys gerenciadas (MANAGED_FEATURES). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"slug":{"type":"string"},"plano":{"type":"string"},"segmento":{"type":"string"},"modulos_ativos":{"type":"array","items":{"type":"string"}},"features_extras":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/verificacao":{"post":{"summary":"Verificar ou suspender selo Varejo Verificado","tags":["Admin - Backoffice"],"description":"Liga (verificar) ou desliga (suspender) o selo Varejo Verificado do tenant. Verificar exige critérios: CNPJ cadastrado, tenant ativo, loja criada e gateway de pagamento ativo. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["acao"],"properties":{"acao":{"type":"string","enum":["verificar","suspender"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tenants/{id}/privacidade":{"patch":{"summary":"Loja privada","tags":["Admin - Backoffice"],"description":"Liga ou desliga a loja privada: ligada, só quem ligou vê a loja no painel, no seletor e no backoffice, mesmo outro super_admin. Os outros vínculos ativos são desativados. `simular: true` só devolve quem perderia o acesso. Exige a área plataforma no próprio perfil (sem o passe livre do super_admin).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["privada"],"properties":{"privada":{"type":"boolean"},"simular":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"privada":{"type":"boolean"},"perdem_acesso":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string","nullable":true},"email":{"type":"string","nullable":true}}}}}}}}}}}},"/tenants/{id}/users":{"get":{"summary":"Listar usuários do tenant","tags":["Admin - Backoffice"],"description":"Retorna todos os profiles vinculados ao tenant, ordenados por data de criação. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar usuário no tenant","tags":["Admin - Backoffice"],"description":"Cria usuário no Supabase Auth + profile vinculado ao tenant. Retorna link de recovery para definição de senha. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","email"],"properties":{"nome":{"type":"string"},"email":{"type":"string","format":"email"},"role":{"type":"string","default":"broker"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/users/{userId}/recovery-link":{"post":{"summary":"Regenerar link de recovery","tags":["Admin - Backoffice"],"description":"Gera novo link de recovery (redefinição de senha) para o usuário do tenant. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"userId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/users/{userId}":{"delete":{"summary":"Remover usuário do tenant","tags":["Admin - Backoffice"],"description":"Remove usuário do Auth e profile do tenant. Auth é removido primeiro (mais crítico). Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"userId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/planos":{"get":{"summary":"Listar planos","tags":["Admin - Backoffice"],"description":"Lista todos os planos ordenados por preço. Aceita filtro por vertical. Requer super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"vertical","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar plano","tags":["Admin - Backoffice"],"description":"Cria novo plano com preço, ciclo, vertical, limites e módulos inclusos. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","slug","preco_centavos","limites","modulos_inclusos"],"properties":{"nome":{"type":"string"},"slug":{"type":"string"},"preco_centavos":{"type":"integer"},"ciclo":{"type":"string","default":"mensal"},"vertical":{"type":"string","default":"imobiliaria"},"limites":{"type":"object"},"modulos_inclusos":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean","default":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/planos/{id}":{"patch":{"summary":"Atualizar plano","tags":["Admin - Backoffice"],"description":"Atualiza campos de um plano existente via allowlist. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"slug":{"type":"string"},"limites":{"type":"object"},"modulos":{"type":"array","items":{"type":"string"}},"vertical":{"type":"string"},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar plano","tags":["Admin - Backoffice"],"description":"Soft delete - marca plano como inativo (ativo=false). Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/ia-custos":{"get":{"summary":"Custos de IA por tenant","tags":["Admin - Backoffice"],"description":"Uso e custo de IA por tenant no mês: agregado mensal (mensagens, copilot, imagens, tokens, custo USD), créditos consumidos, limites efetivos (plano + override) e breakdown por serviço/recurso do ledger ia_uso_eventos. Requer super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"mes","required":false,"description":"Mês no formato YYYY-MM (default: mês atual)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/imobiliarias/{id}/ia-limites":{"patch":{"summary":"Override de limites de IA do tenant","tags":["Admin - Backoffice"],"description":"Define override de limites de IA (imobiliarias.ia_limites). Chave com valor null remove o override (volta a herdar do plano); objeto resultante vazio zera a coluna (null). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mensagens_ia":{"type":["integer","null"],"minimum":0},"copilot_mensagens":{"type":["integer","null"],"minimum":0},"creditos_ia":{"type":["integer","null"],"minimum":0}},"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ia-precos":{"get":{"summary":"Listar preços por modelo de IA","tags":["Admin - Backoffice"],"description":"Lista ia_modelo_precos (USD por milhão de tokens input/output + custo por unidade). Base do cálculo de custo da RPC ia_registrar_uso. Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Atualizar preços por modelo de IA","tags":["Admin - Backoffice"],"description":"Upsert em ia_modelo_precos por modelo. Aceita lista de modelos com preços USD. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["precos"],"properties":{"precos":{"type":"array","minItems":1,"items":{"type":"object","required":["modelo"],"properties":{"modelo":{"type":"string","minLength":1},"input_por_milhao_usd":{"type":"number","minimum":0},"output_por_milhao_usd":{"type":"number","minimum":0},"por_unidade_usd":{"type":"number","minimum":0}},"additionalProperties":false}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/ia-precos-acao":{"get":{"summary":"Listar créditos IA por ação","tags":["Admin - Backoffice"],"description":"Lista ia_precos_acao: quantos Créditos IA cada ação de IA consome (Eva, imagem, descrição...). Requer financeiro.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Atualizar créditos IA por ação","tags":["Admin - Backoffice"],"description":"Atualiza ia_precos_acao.creditos das ações existentes. Ação nova é migration, não tela. Requer financeiro.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["precos"],"properties":{"precos":{"type":"array","minItems":1,"items":{"type":"object","required":["acao","creditos"],"properties":{"acao":{"type":"string","minLength":1},"creditos":{"type":"integer","minimum":1,"maximum":100000}},"additionalProperties":false}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tenants/{id}/billing":{"get":{"summary":"Billing do tenant","tags":["Admin - Backoffice"],"description":"Retorna assinatura (com plano), faturas, status de enforcement, trilha de auditoria de billing e as últimas tentativas de contratar, trocar de plano ou reativar (com o motivo da recusa). Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/take-rate":{"put":{"summary":"Editar take rate do tenant","tags":["Admin - Backoffice"],"description":"Define o percentual cobrado do tenant sobre pedidos pagos fora do Varejo Pay. Base 10000 (100 = 1%). null remove o override. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"percentual":{"type":["integer","null"]}},"required":["percentual"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/config/take-rate-global":{"put":{"summary":"Editar take rate padrão global","tags":["Admin - Backoffice"],"description":"Define o percentual padrão cobrado de tenants sem override. Base 10000 (100 = 1%). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"percentual":{"type":"integer"}},"required":["percentual"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/cortesia":{"post":{"summary":"Conceder cortesia","tags":["Admin - Backoffice"],"description":"Coloca a assinatura em status cortesia e libera a plataforma sem gerar fatura ate a data. Nenhuma cobranca e emitida. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cortesia_ate","motivo"],"properties":{"cortesia_ate":{"type":"string"},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/temas/{templateId}/cortesia":{"post":{"summary":"Conceder tema em cortesia","tags":["Admin - Backoffice"],"description":"Concede a licenca de um tema pago ao tenant emitindo uma fatura de VALOR CHEIO e isentando-a na hora (spec 2026-08-02 secao 6) — o desconto vira registro financeiro rastreavel, nunca brinde invisivel. Recusa com 409 se o tenant ja possui licenca ATIVA deste tema (revogue antes de conceder cortesia — nunca sobrescreve uma venda ja feita). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo"],"properties":{"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"templateId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"slug":{"type":"string"},"origem":{"type":"string"},"status":{"type":"string"},"numero":{"type":"string"},"fatura_id":{"type":"string"}}}}}}}}},"/tenants/{id}/billing/estender-trial":{"post":{"summary":"Estender trial","tags":["Admin - Backoffice"],"description":"Move trial_fim_em para uma nova data futura e zera a inadimplencia. Sem cobranca. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["trial_fim_em","motivo"],"properties":{"trial_fim_em":{"type":"string"},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/iniciar-trial":{"post":{"summary":"Iniciar trial","tags":["Admin - Backoffice"],"description":"Cria a linha de assinatura em trial para tenant provisionado sem billing (implantacao). A partir dela, cortesia/estender/suspender passam a operar. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["plano_id","trial_fim_em","motivo"],"properties":{"plano_id":{"type":"string","format":"uuid"},"trial_fim_em":{"type":"string"},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/faturas/{fid}/isentar":{"post":{"summary":"Isentar fatura (cortesia)","tags":["Admin - Backoffice"],"description":"Quita a fatura como cortesia, sem cobrar o meio de pagamento. Entra no financeiro como desconto concedido (receita recebida = 0) e zera a inadimplencia. A fatura nao e apagada. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo"],"properties":{"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"fid","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/faturas/{fid}/marcar-paga":{"post":{"summary":"Registrar pagamento por fora","tags":["Admin - Backoffice"],"description":"Marca a fatura como paga (metodo manual_offline), preservando o valor recebido no historico, e zera a inadimplencia. Para Pix direto, dinheiro ou transferencia. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["observacao"],"properties":{"observacao":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"fid","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/suspender":{"post":{"summary":"Suspender tenant","tags":["Admin - Backoffice"],"description":"Coloca a assinatura em suspended (tela de reativacao). Dados preservados. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tenants/{id}/billing/reativar":{"post":{"summary":"Reativar tenant","tags":["Admin - Backoffice"],"description":"Reabilita a assinatura (status active, inadimplencia zerada). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tema-templates/{idOrSlug}":{"patch":{"summary":"Editar conteúdo do tema (Theme Store)","tags":["Admin - Backoffice"],"description":"Edita o conteúdo promocional da página de detalhe do tema (/loja/temas/[slug]): imagem promocional, descrição longa, recursos curados, destaques e screenshots. Aceita id (uuid) ou slug em :idOrSlug. Whitelist estrita — NUNCA aceita slug, config, templates, paginas, preco_centavos ou ativo (identidade, conteúdo funcional e preço do tema; alterá-los por aqui quebraria licença/renderização). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"imagem_promocional_url":{"type":["string","null"]},"descricao_longa":{"type":["string","null"]},"recursos":{"type":"array"},"destaques":{"type":"array"},"screenshots":{"type":"array"}}}}}},"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"idOrSlug","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/planos":{"get":{"summary":"Listar planos disponíveis","tags":["Billing - Faturamento"],"description":"Retorna planos ativos ordenados por preço. Filtro opcional por vertical.","parameters":[{"schema":{"type":"string"},"in":"query","name":"vertical","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/billing/assinatura":{"get":{"summary":"Consultar assinatura atual","tags":["Billing - Faturamento"],"description":"Retorna a assinatura do tenant com dados do plano. Null se não houver.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"additionalProperties":true}}}}}},"post":{"summary":"Criar assinatura","tags":["Billing - Faturamento"],"description":"Cria customer no Asaas + subscription + registro local. Suporta boleto, pix e cartão (com validação PCI-DSS: Luhn, CVV, validade).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["plano_id","metodo_pagamento","nome","cpf_cnpj"],"properties":{"plano_id":{"type":"string","format":"uuid"},"metodo_pagamento":{"type":"string","enum":["boleto","pix","cartao"]},"nome":{"type":"string"},"cpf_cnpj":{"type":"string"},"email":{"type":"string"},"telefone":{"type":"string"},"cartao":{"type":"object","description":"Dados do cartão (obrigatório se método = cartao e cartao_gateway = asaas)"},"cartao_token":{"type":"string","description":"Token do cartão gerado no navegador pelo Pagar.me (token_...). Com cartao_gateway = pagarme."},"cartao_titular":{"type":"object","description":"Titular e endereço de cobrança do cartão (o token não leva endereço): nome, cpf_cnpj, email, telefone, cep, numero; opcionais rua, bairro, cidade, uf, complemento.","additionalProperties":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/troca-previa":{"get":{"summary":"Prévia da troca de plano","tags":["Billing - Faturamento"],"description":"Diz se a troca vale na hora (com a diferença proporcional, liberada quando paga) ou fica agendada para o fim do período pago, sem alterar nada.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"plano_id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/upgrade":{"post":{"summary":"Upgrade ou downgrade de plano","tags":["Billing - Faturamento"],"description":"Upgrade no mesmo ciclo cobra a diferença proporcional e o plano novo vale quando ela é paga (na hora, sem diferença); downgrade e troca de ciclo ficam agendados para o fim do período pago. Valida catálogo, segmento, situação da assinatura e limites de uso.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["plano_id"],"properties":{"plano_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/troca-pendente":{"delete":{"summary":"Desistir do upgrade aguardando pagamento","tags":["Billing - Faturamento"],"description":"Cancela a cobrança da diferença ainda não paga. O plano continua o atual.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/troca-agendada":{"delete":{"summary":"Cancelar troca de plano agendada","tags":["Billing - Faturamento"],"description":"Desfaz o downgrade ou a troca de ciclo agendados: a assinatura volta a cobrar o plano atual a partir do fim do período.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/cancelar":{"post":{"summary":"Cancelar assinatura","tags":["Billing - Faturamento"],"description":"Assinatura paga: nada mais é cobrado e o acesso vale até o fim do período pago (cancelar_em). Assinatura nunca paga: cancela na hora.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"cancelar_em":{"type":["null","string"]},"contratacao_desfeita":{"type":"boolean"}}}}}}}}},"/billing/assinatura/desfazer-cancelamento":{"post":{"summary":"Desfazer cancelamento agendado","tags":["Billing - Faturamento"],"description":"Volta a cobrar a partir do fim do período pago, como se nada tivesse sido cancelado.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/assinatura/metodo":{"put":{"summary":"Alterar método de pagamento","tags":["Billing - Faturamento"],"description":"Troca a forma de pagamento da assinatura (boleto, pix ou cartão). No cartão, o cartão novo é tokenizado e trocado pelo endpoint próprio do Asaas, sem cobrar; as cobranças pendentes passam a usá-lo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["metodo_pagamento"],"properties":{"metodo_pagamento":{"type":"string","enum":["boleto","pix","cartao"]},"cartao":{"type":"object","description":"Dados do cartão (obrigatório se método = cartao e cartao_gateway = asaas)"},"cartao_token":{"type":"string","description":"Token do cartão gerado no navegador pelo Pagar.me (token_...). Com cartao_gateway = pagarme."},"cartao_titular":{"type":"object","description":"Titular e endereço de cobrança do cartão (o token não leva endereço): nome, cpf_cnpj, email, telefone, cep, numero; opcionais rua, bairro, cidade, uf, complemento.","additionalProperties":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/faturas":{"get":{"summary":"Listar faturas","tags":["Billing - Faturamento"],"description":"Retorna faturas do tenant com paginação. Ordenadas por vencimento decrescente.","parameters":[{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"number"},"limit":{"type":"number"},"offset":{"type":"number"}}}}}}}}},"/billing/faturas/{id}/pix":{"get":{"summary":"Gerar Pix de uma fatura","tags":["Billing - Faturamento"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/uso":{"get":{"summary":"Consultar uso e limites do plano","tags":["Billing - Faturamento"],"description":"Retorna uso atual vs limites do plano (imóveis, produtos, usuários, storage, IA, WhatsApp, NFS-e) com créditos extras.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/pacotes-whatsapp":{"get":{"summary":"Listar pacotes de créditos WhatsApp","tags":["Billing - Faturamento"],"description":"Retorna pacotes ativos de créditos de mensagens ordenados por quantidade.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/billing/creditos-whatsapp":{"get":{"summary":"Consultar créditos WhatsApp","tags":["Billing - Faturamento"],"description":"Retorna histórico de créditos e saldo total ativo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"creditos":{"type":"array","items":{"type":"object","additionalProperties":true}},"saldo":{"type":"number"},"saldo_por_tipo":{"type":"object","additionalProperties":{"type":"number"}}}}}}}}},"post":{"summary":"Comprar pacote de créditos WhatsApp","tags":["Billing - Faturamento"],"description":"Cria pagamento avulso no Asaas (Pix ou cartão). Retorna QR code Pix se aplicável. Crédito ativado imediatamente se cartão confirmou na hora.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pacote_id"],"properties":{"pacote_id":{"type":"string","format":"uuid"},"metodo":{"type":"string","enum":["pix","cartao"]},"nome":{"type":"string","description":"Responsável financeiro (só quando a loja ainda não tem cadastro de cobrança, ex.: cortesia)"},"cpf_cnpj":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/creditos-whatsapp/{paymentId}/status":{"get":{"summary":"Verificar status de pagamento de créditos WhatsApp","tags":["Billing - Faturamento"],"description":"Polling: consulta status no Asaas e ativa crédito se confirmado (idempotente).","parameters":[{"schema":{"type":"string"},"in":"path","name":"paymentId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"credito_status":{"type":"string"}}}}}}}}},"/billing/pacotes-nfse":{"get":{"summary":"Listar pacotes de créditos NFS-e","tags":["Billing - Faturamento"],"description":"Retorna pacotes ativos de créditos de notas fiscais.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/billing/creditos-nfse":{"get":{"summary":"Consultar créditos NFS-e","tags":["Billing - Faturamento"],"description":"Retorna histórico de créditos NFS-e e saldo total ativo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"creditos":{"type":"array","items":{"type":"object","additionalProperties":true}},"saldo":{"type":"number"}}}}}}}},"post":{"summary":"Comprar pacote de créditos NFS-e","tags":["Billing - Faturamento"],"description":"Cria pagamento Pix avulso no Asaas para compra de créditos de notas fiscais. Validade 1 ano.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pacote_id"],"properties":{"pacote_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/creditos-nfse/{paymentId}/status":{"get":{"summary":"Verificar status de pagamento de créditos NFS-e","tags":["Billing - Faturamento"],"description":"Polling: consulta status no Asaas e ativa crédito NFS-e se confirmado.","parameters":[{"schema":{"type":"string"},"in":"path","name":"paymentId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"credito_status":{"type":"string"}}}}}}}}},"/billing/reativar":{"post":{"summary":"Reativar conta suspensa","tags":["Billing - Faturamento"],"description":"Cancela subscription antiga no Asaas, cria nova, reseta inadimplência e restaura plano.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["metodo_pagamento"],"properties":{"metodo_pagamento":{"type":"string","enum":["boleto","pix","cartao"]},"cartao":{"type":"object","description":"Dados do cartão (obrigatório se método = cartao e cartao_gateway = asaas)"},"cartao_token":{"type":"string","description":"Token do cartão gerado no navegador pelo Pagar.me (token_...). Com cartao_gateway = pagarme."},"cartao_titular":{"type":"object","description":"Titular e endereço de cobrança do cartão (o token não leva endereço): nome, cpf_cnpj, email, telefone, cep, numero; opcionais rua, bairro, cidade, uf, complemento.","additionalProperties":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"proximo_vencimento":{"type":"string"}}}}}}}}},"/billing/webhook":{"post":{"summary":"Webhook de billing do Asaas","tags":["Billing - Faturamento"],"description":"Rota pública. Valida ASAAS_WEBHOOK_TOKEN (header ou query). Processa PAYMENT_CONFIRMED/RECEIVED (faturas, créditos WhatsApp/NFS-e, comissões de parceiro), PAYMENT_OVERDUE, PAYMENT_CREATED (cria fatura + Pix), PAYMENT_DELETED/REFUNDED (estorno de comissão).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"payment":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/billing/config-pagamento":{"get":{"summary":"Onde o cartão é cobrado","tags":["Billing - Faturamento"],"description":"cartao_gateway = pagarme só quando PAGARME_SECRET_KEY e PAGARME_PUBLIC_KEY existem; nesse caso a tela tokeniza o cartão com pagarme_public_key e manda cartao_token + cartao_titular. Com asaas, o corpo antigo (cartao).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cartao_gateway":{"type":"string","enum":["pagarme","asaas"]},"pagarme_public_key":{"type":"string","nullable":true}}}}}}}}},"/billing/webhook/pagarme":{"post":{"summary":"Webhook da mensalidade no Pagar.me","tags":["Billing - Faturamento"],"description":"Rota pública. Autenticação igual ao webhook de pedidos: x-hub-signature com HMAC sha256 do corpo (sha256=<hex>) ou o segredo PAGARME_WEBHOOK_SECRET. Trata invoice.paid, invoice.payment_failed, invoice.canceled, order.paid, order.payment_failed, charge.paid, charge.payment_failed, charge.refunded e subscription.canceled da mensalidade; o resto responde 200 ignorado. Idempotente pelo ledger de eventos.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/platform-fees":{"post":{"summary":"Processar taxas de plataforma (interno)","tags":["Billing - Faturamento"],"description":"Trigger manual do faturamento da taxa de 1%. Protegido por x-internal-key.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/billing/payment-link":{"post":{"summary":"Criar link de pagamento Pix via Pagar.me","tags":["Checkout - Link de Pagamento"],"description":"Cria customer e order no Pagar.me com pagamento Pix (QR Code). Suporta split de pagamento opcional. Retorna QR code e URL de pagamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"integer","description":"Valor em centavos"},"customer":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"document":{"type":"string","description":"CPF ou CNPJ"},"phone":{"type":"string"}},"required":["name","email","document"]},"items":{"type":"array","items":{"type":"object","properties":{"description":{"type":"string"},"quantity":{"type":"integer"},"amount":{"type":"integer"}},"required":["description","quantity","amount"]},"minItems":1},"external_reference":{"type":"string"},"split":{"type":"object","properties":{"recipient_id":{"type":"string"},"percentage":{"type":"number"}},"nullable":true}},"required":["amount","customer","items","external_reference"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"charge_id":{"type":"string"},"payment_url":{"type":"string","nullable":true},"pix_qrcode":{"type":"string","nullable":true}}}}}}}}},"/billing/payment-link-internal":{"post":{"summary":"Criar link de pagamento interno (service-to-service)","tags":["Checkout - Link de Pagamento"],"description":"Cria cobrança Pix no Pagar.me para chamadas internas (IA do Connect). Autenticação via header X-Service-Key. Aplica split com recipient do tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","format":"uuid"},"amount":{"type":"integer","description":"Valor em centavos"},"description":{"type":"string"},"pedido_id":{"type":"string","format":"uuid","nullable":true}},"required":["account_id","amount"]}}},"required":true},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"order_id":{"type":"string"},"charge_id":{"type":"string"},"payment_url":{"type":"string","nullable":true},"pix_qrcode":{"type":"string","nullable":true}}}}}}}}},"/marketing/coleta":{"get":{"summary":"Coleta de eventos da loja","tags":["Marketing - Tracking"],"description":"Devolve a hora em que a loja parou de enviar eventos de tracking, enquanto o silêncio estiver aberto, e desde quando a Meta recusa o token, o pixel ou a permissão da loja; null quando está normal.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/marketing/dashboard":{"get":{"summary":"Dashboard de marketing","tags":["Marketing - Tracking"],"description":"Visão operacional: KPIs (sessões, vendas, conversão), top canais, campanhas UTM/cupom e automações ativas. Período 7/30/90d.","parameters":[{"schema":{"type":"string","enum":["7d","30d","90d"],"default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/marketing/ritmo":{"get":{"summary":"Ritmo do mês corrente","tags":["Marketing - Metas"],"description":"Onde a loja está contra a meta do mês: vendido até ontem, projeção de fechamento, ritmo necessário, série acumulada do gráfico e as três alavancas (sessões, conversão e ticket) já julgadas. Sem meta no mês, traz a sugestão pelos últimos 90 dias fechados (ou o motivo de não haver). Guardado por 5 min por loja; salvar a meta apaga o guardado.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/marketing/metas":{"get":{"summary":"Metas do ano","tags":["Marketing - Metas"],"description":"Os 12 meses do ano com a meta (se houver), o vendido, o atingimento (vendido ÷ meta de vendas) e se o mês pode ser editado (mês corrente ou futuro). Mês futuro vem sem vendido. Sem `ano`, usa o ano corrente.","parameters":[{"schema":{"type":"string"},"in":"query","name":"ano","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/marketing/metas/sugestao":{"get":{"summary":"Sugestão de meta pelo histórico","tags":["Marketing - Metas"],"description":"Sugere sessões, conversão e ticket do mês (corrente ou futuro) pelo ritmo da própria loja nos 90 dias fechados antes de hoje, com os atalhos manter, crescer 10% e crescer 20%. Sem histórico suficiente devolve `{ motivo }` (historico_curto, poucas_sessoes ou sem_pedidos) no lugar de `{ sugestao }`.","parameters":[{"schema":{"type":"string"},"in":"query","name":"mes","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/marketing/metas/{mes}":{"put":{"summary":"Gravar a meta de um mês","tags":["Marketing - Metas"],"description":"Grava (upsert por loja e mês) a meta do mês `AAAA-MM`, que precisa ser o corrente ou futuro. Corpo: `{ sessoes: inteiro >= 0, conversao: fração de 0 a 1 (0,02 é 2%), ticket_centavos: inteiro >= 0, origem?: \"sugestao\" | \"manual\" }`. Responde `{ mes, meta }` com a meta como ficou no banco.","parameters":[{"schema":{"type":"string"},"in":"path","name":"mes","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/midia/contas":{"get":{"summary":"Estado da conexão com o Google Ads (investimento)","tags":["Marketing - Mídia"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/midia/google/contas-disponiveis":{"get":{"summary":"Contas do Google Ads que o login autorizado enxerga","tags":["Marketing - Mídia"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/midia/google/conta":{"post":{"summary":"Escolher a conta do Google Ads da loja","tags":["Marketing - Mídia"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["conta_id"],"properties":{"conta_id":{"type":"string","minLength":1,"maxLength":20}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/midia/google/sincronizar":{"post":{"summary":"Puxar o investimento do Google Ads agora","tags":["Marketing - Mídia"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/midia/google":{"delete":{"summary":"Parar de puxar o investimento do Google Ads","tags":["Marketing - Mídia"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/dashboard":{"get":{"summary":"Dashboard de inteligência","tags":["Inteligência - Analytics"],"description":"KPIs: imóveis ativos, valor médio, leads do mês, taxa de conversão e sparkline 6 meses.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/portfolio":{"get":{"summary":"Portfólio por tipo","tags":["Inteligência - Analytics"],"description":"Agrupamento de imóveis por tipo com quantidade, valor médio e taxa de ocupação.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/clientes":{"get":{"summary":"Customer 360","tags":["Inteligência - Analytics"],"description":"KPIs unificados: distribuição por lifecycle_stage, LTV total e médio, top 10 clientes e canais de origem.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/funil":{"get":{"summary":"Funil de leads","tags":["Inteligência - Analytics"],"description":"Leads por etapa do pipeline com taxa de conversão e percentual do funil.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/precificacao":{"post":{"summary":"Precificação inteligente","tags":["Inteligência - Analytics"],"description":"Comparativo de preços por tipo, bairro e cidade. Retorna média, min, max e nível de confiança.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"finalidade":{"type":"string"},"area_util":{"type":"number"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/relatorios":{"get":{"summary":"Relatórios de inteligência","tags":["Inteligência - Analytics"],"description":"Placeholder para relatórios avançados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/inteligencia/benchmarking":{"get":{"summary":"Benchmarking","tags":["Inteligência - Analytics"],"description":"Métricas do tenant vs média global (imóveis, valor médio, leads, conversão).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/dashboard":{"get":{"summary":"Dashboard financeiro","tags":["Financeiro - Hub Cash"],"description":"Receitas, despesas, saldo do mês e comissões pendentes.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/lancamentos":{"get":{"summary":"Listar lançamentos","tags":["Financeiro - Hub Cash"],"description":"Lançamentos paginados com filtros por tipo, status, período, plano de contas, centro de custo e busca.","parameters":[{"schema":{"type":"integer"},"in":"query","name":"page","required":false},{"schema":{"type":"integer"},"in":"query","name":"pageSize","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"de","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false},{"schema":{"type":"string"},"in":"query","name":"plano_contas_id","required":false},{"schema":{"type":"string"},"in":"query","name":"centro_custo_id","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar lançamento","tags":["Financeiro - Hub Cash"],"description":"Cadastra novo lançamento financeiro (receita ou despesa).","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/cash/lancamentos/{id}":{"patch":{"summary":"Atualizar lançamento","tags":["Financeiro - Hub Cash"],"description":"Atualização parcial de lançamento financeiro.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir lançamento","tags":["Financeiro - Hub Cash"],"description":"Remove lançamento financeiro.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/comissoes":{"get":{"summary":"Listar comissões","tags":["Financeiro - Hub Cash"],"description":"Comissões com filtros por corretor, status e período.","parameters":[{"schema":{"type":"string"},"in":"query","name":"corretor_id","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"de","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar comissão","tags":["Financeiro - Hub Cash"],"description":"Registra comissão para corretor. Requer manager ou superior.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/cash/comissoes/{id}/pagar":{"post":{"summary":"Pagar comissão","tags":["Financeiro - Hub Cash"],"description":"Marca comissão como paga com data de pagamento. Requer manager ou superior.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/fluxo":{"get":{"summary":"Fluxo de caixa","tags":["Financeiro - Hub Cash"],"description":"Receitas, despesas e saldo agrupados por mês nos últimos N meses.","parameters":[{"schema":{"type":"integer","default":12},"in":"query","name":"meses","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/dre":{"get":{"summary":"DRE","tags":["Financeiro - Hub Cash"],"description":"Demonstrativo de resultado agrupado por plano de contas no período.","parameters":[{"schema":{"type":"string"},"in":"query","name":"de","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/plano-contas":{"get":{"summary":"Plano de contas","tags":["Financeiro - Hub Cash"],"description":"Lista hierárquica do plano de contas do tenant.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cash/centros-custo":{"get":{"summary":"Centros de custo","tags":["Financeiro - Hub Cash"],"description":"Lista centros de custo do tenant.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/relatorios":{"get":{"summary":"Relatório por vertical","tags":["Relatórios"],"description":"Métricas específicas por segmento do tenant (imobiliária, varejo, pet, saúde, serviços). Inclui agendamentos, serviços, portfólio e catálogo conforme vertical.","parameters":[{"schema":{"type":"integer","default":30},"in":"query","name":"dias","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me":{"get":{"summary":"Perfil do parceiro","tags":["Parceiros - Afiliados"],"description":"Retorna dados do parceiro autenticado com tier atual.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar perfil","tags":["Parceiros - Afiliados"],"description":"Atualiza nome, telefone, bio, avatar e dados Pix.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"telefone":{"type":["string","null"]},"bio":{"type":["string","null"]},"pix_tipo":{"type":["string","null"]},"pix_chave":{"type":["string","null"]},"avatar_url":{"type":["string","null"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/dashboard":{"get":{"summary":"Dashboard do parceiro","tags":["Parceiros - Afiliados"],"description":"Métricas do parceiro: vendas do mês, comissões, saldo, cliques, taxa de conversão e progresso para próximo tier.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/vendas":{"get":{"summary":"Listar vendas do parceiro","tags":["Parceiros - Afiliados"],"description":"Vendas do parceiro com paginação e filtro por status.","parameters":[{"schema":{"type":"integer"},"in":"query","name":"page","required":false},{"schema":{"type":"integer"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/financeiro":{"get":{"summary":"Financeiro do parceiro","tags":["Parceiros - Afiliados"],"description":"Saldo disponível, pendente, totais e histórico de saques.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/saques":{"post":{"summary":"Solicitar saque","tags":["Parceiros - Afiliados"],"description":"Solicita saque (mín. R$100). Exige KYC aprovado, Pix configurado e NFS-e de serviço (agenciamento, LC 116 10.02) anexada. Débito atômico contra race condition.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["valor_centavos","nfse_numero","nfse_url"],"properties":{"valor_centavos":{"type":"integer"},"nfse_numero":{"type":"string"},"nfse_url":{"type":"string"},"nfse_codigo_servico":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/extrato":{"get":{"summary":"Extrato de comissão","tags":["Parceiros - Afiliados"],"description":"Apuração de comissão do parceiro por lojista e mês: TPV, margem gerada (MCL), comissão e status (pendente/liberada).","parameters":[{"schema":{"type":"string"},"in":"query","name":"mes","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/contrato":{"get":{"summary":"Contrato de parceria","tags":["Parceiros - Afiliados"],"description":"Texto vigente do contrato e status de aceite do parceiro.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/contrato/aceitar":{"post":{"summary":"Aceitar contrato","tags":["Parceiros - Afiliados"],"description":"Registra o aceite da versão vigente do contrato de parceria.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/materiais":{"get":{"summary":"Materiais de treinamento","tags":["Parceiros - Afiliados"],"description":"Lista materiais ativos com filtro por categoria e tipo.","parameters":[{"schema":{"type":"string"},"in":"query","name":"categoria","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/ranking":{"get":{"summary":"Ranking de parceiros","tags":["Parceiros - Afiliados"],"description":"Top 20 parceiros aprovados do mês por vendas.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/link":{"get":{"summary":"Link de afiliado","tags":["Parceiros - Afiliados"],"description":"Retorna slug, URL completa e dados para QR code.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/parceiros/me/cliques":{"get":{"summary":"Cliques do parceiro","tags":["Parceiros - Afiliados"],"description":"Cliques agrupados por dia nos últimos 30 dias.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/parceiro/{slug}":{"get":{"summary":"Validar parceiro por slug","tags":["Parceiros - Público"],"description":"Retorna dados públicos do parceiro se aprovado.","parameters":[{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/public/parceiro/registro":{"post":{"summary":"Auto-cadastro de parceiro","tags":["Parceiros - Público"],"description":"Registro público de parceiro. Cria Auth user + profile parceiro com status pendente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","email","senha"],"properties":{"nome":{"type":"string"},"email":{"type":"string"},"telefone":{"type":"string"},"documento":{"type":"string"},"senha":{"type":"string"}}}}},"required":true},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/parceiro/clique":{"post":{"summary":"Registrar clique","tags":["Parceiros - Público"],"description":"Registra clique no link de afiliado com dados de UTM e referrer.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["parceiro_id"],"properties":{"parceiro_id":{"type":"string"},"ip":{"type":"string"},"user_agent":{"type":"string"},"referrer":{"type":"string"},"utm_source":{"type":"string"},"utm_medium":{"type":"string"},"utm_campaign":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros":{"get":{"summary":"Listar parceiros","tags":["Parceiros - Admin"],"description":"Lista paginada de parceiros com filtros por status, tipo e busca. Requer super_admin.","parameters":[{"schema":{"type":"integer"},"in":"query","name":"page","required":false},{"schema":{"type":"integer"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar parceiro (admin)","tags":["Parceiros - Admin"],"description":"Cria parceiro já aprovado via backoffice. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","email"],"properties":{"nome":{"type":"string"},"email":{"type":"string"},"telefone":{"type":"string"},"tipo":{"type":"string","enum":["externo","interno"]},"senha":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/parceiros/{id}":{"get":{"summary":"Detalhe do parceiro","tags":["Parceiros - Admin"],"description":"Retorna parceiro com vendas e saques recentes. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/{id}/aprovar":{"post":{"summary":"Aprovar parceiro","tags":["Parceiros - Admin"],"description":"Aprova parceiro pendente. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/{id}/bloquear":{"post":{"summary":"Bloquear parceiro","tags":["Parceiros - Admin"],"description":"Bloqueia parceiro ativo. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/vendas":{"get":{"summary":"Todas as vendas de parceiros","tags":["Parceiros - Admin"],"description":"Lista paginada de todas as vendas com filtro por status. Requer super_admin.","parameters":[{"schema":{"type":"integer"},"in":"query","name":"page","required":false},{"schema":{"type":"integer"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/saques":{"get":{"summary":"Listar saques","tags":["Parceiros - Admin"],"description":"Saques pendentes ou filtrados por status. Requer super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/saques/{id}":{"patch":{"summary":"Aprovar/rejeitar saque","tags":["Parceiros - Admin"],"description":"Aprova ou rejeita saque. Se rejeitado, estorna saldo via incremento atômico. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["aprovado","rejeitado"]},"observacoes":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/saques/{id}/pagar":{"post":{"summary":"Marcar saque como pago","tags":["Parceiros - Admin"],"description":"Marca saque aprovado como pago com data e comprovante opcional. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comprovante_url":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/rate-card":{"get":{"summary":"Rate card de comissão","tags":["Parceiros - Admin"],"description":"Lista o rate card (bps por trilho/método/tier). Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar entrada de rate card","tags":["Parceiros - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["trilho","repasse_bps"],"properties":{"trilho":{"type":"string","enum":["rekta_pay","third_party"]},"metodo":{"type":["string","null"]},"tier_slug":{"type":["string","null"]},"plano_id":{"type":["string","null"]},"repasse_bps":{"type":"integer"},"teto_bps":{"type":["integer","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/parceiros/rate-card/{id}":{"patch":{"summary":"Atualizar rate card","tags":["Parceiros - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover entrada de rate card","tags":["Parceiros - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/{id}/kyc":{"post":{"summary":"Validar KYC do parceiro","tags":["Parceiros - Admin"],"description":"Aprova/reprova o KYC (bloqueia liberação/saque) e registra optante do Simples (dispensa IRRF). Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["kyc_status"],"properties":{"kyc_status":{"type":"string","enum":["aprovado","reprovado","pendente"]},"razao_social":{"type":"string"},"nfse_email":{"type":"string"},"optante_simples":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/apuracao":{"get":{"summary":"Apuração de comissão do motor","tags":["Parceiros - Admin"],"description":"Lista a apuração de comissão (MCL, trava, comissão) por lojista/mês. Requer super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"mes","required":false},{"schema":{"type":"string"},"in":"query","name":"parceiro_id","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/tiers/{id}":{"get":{"summary":"Detalhe do tier","tags":["Parceiros - Admin"],"description":"Retorna configuração de um tier. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar tier","tags":["Parceiros - Admin"],"description":"Atualiza configuração de tier via allowlist. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover tier","tags":["Parceiros - Admin"],"description":"Exclui tier de parceiro. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/materiais":{"get":{"summary":"Listar materiais","tags":["Parceiros - Admin"],"description":"Lista todos os materiais de treinamento ordenados. Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar material","tags":["Parceiros - Admin"],"description":"Cadastra material de treinamento. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["titulo","tipo","url"],"properties":{"titulo":{"type":"string"},"descricao":{"type":"string"},"tipo":{"type":"string"},"categoria":{"type":"string"},"url":{"type":"string"},"thumbnail_url":{"type":"string"},"duracao_segundos":{"type":"integer"},"ordem":{"type":"integer"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/parceiros/materiais/{id}":{"patch":{"summary":"Atualizar material","tags":["Parceiros - Admin"],"description":"Atualiza material via allowlist. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir material","tags":["Parceiros - Admin"],"description":"Remove material de treinamento. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/config":{"get":{"summary":"Configurações do programa","tags":["Parceiros - Admin"],"description":"Retorna configurações do programa de parceiros como mapa chave-valor. Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar configurações","tags":["Parceiros - Admin"],"description":"Atualiza configurações do programa de parceiros por chave-valor. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar configuração","tags":["Parceiros - Admin"],"description":"Adiciona nova chave de configuração ao programa. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["chave","valor"],"properties":{"chave":{"type":"string"},"valor":{"type":"string"},"descricao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/parceiros/config/{id}":{"delete":{"summary":"Excluir configuração","tags":["Parceiros - Admin"],"description":"Remove entrada de configuração do programa. Requer super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/admin/parceiros/tiers":{"get":{"summary":"Listar todos os tiers","tags":["Parceiros - Admin"],"description":"Retorna tiers ordenados. Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar tier","tags":["Parceiros - Admin"],"description":"Cria novo tier de parceiro com comissões e limites. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"icone":{"type":"string"},"cor":{"type":"string"},"vendas_min":{"type":"integer"},"vendas_max":{"type":["integer","null"]},"comissao_mensal":{"type":"number"},"comissao_anual":{"type":"number"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/parceiros/stats":{"get":{"summary":"Dashboard admin parceiros","tags":["Parceiros - Admin"],"description":"Totais globais: parceiros, pendentes, aprovados, vendas, comissões e saques pendentes. Requer super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pedidos":{"post":{"summary":"Criar pedido via checkout público","tags":["OMS - Pedidos"],"description":"Endpoint de checkout da loja virtual (sem JWT). Valida itens, estoque, cupom, promoções automáticas, preço de volume (B2C/B2B), frete, gift wrap, antifraude e cria cobrança no gateway. Suporta idempotência via Idempotency-Key. Suporta promoção de rascunho (Shopify Draft Order) via session_token. Rate-limited: 10 req/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","format":"uuid"},"itens":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer","minimum":1}}},"minItems":1},"cliente":{"type":"object","properties":{"nome":{"type":"string"},"email":{"type":"string"},"telefone":{"type":"string"},"cpf":{"type":"string"},"cnpj":{"type":"string","nullable":true},"razao_social":{"type":"string","nullable":true},"ie":{"type":"string","nullable":true}},"required":["nome","telefone"]},"endereco":{"type":"object","properties":{"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"}}},"endereco_cobranca":{"type":"object","properties":{"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"}}},"frete":{"type":"object","properties":{"tipo":{"type":"string"},"preco_centavos":{"type":"integer"},"prazo_dias":{"type":"integer"},"provider":{"type":"string","nullable":true},"servico_id":{"type":"integer","nullable":true},"servico_codigo":{"type":"string","nullable":true},"shipping_rule_id":{"type":"string","nullable":true},"partes":{"type":"array","items":{"type":"object","additionalProperties":true},"nullable":true}}},"forma_pagamento":{"type":"string","enum":["pix","boleto","credit_card","whatsapp"]},"session_token":{"type":"string","nullable":true,"description":"Session token para promover rascunho existente"},"cupom_id":{"type":"string","format":"uuid","nullable":true},"cupom_codigo":{"type":"string","nullable":true},"tipo_entrega":{"type":"string","enum":["envio","retirada"]},"b2b_unidade_id":{"type":"string","format":"uuid","nullable":true},"po_number":{"type":"string","nullable":true},"payment_term":{"type":"string","enum":["a_vista_pix","boleto_30","boleto_60","boleto_90"],"nullable":true},"creditos_usados_centavos":{"type":"integer","minimum":0,"nullable":true},"termo_aceite":{"type":"object","nullable":true,"properties":{"termo_versao_id":{"type":"string"}}},"agendamento":{"type":"object","nullable":true,"properties":{"janela_id":{"type":"string","format":"uuid"},"data":{"type":"string"},"cart_session_id":{"type":"string"}}}},"required":["account_id","itens","cliente","forma_pagamento"]}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"numero":{"type":"string"},"total":{"type":"integer"},"idempotent":{"type":"boolean"}}}}}},"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Listar pedidos","tags":["OMS - Pedidos"],"description":"Retorna PEDIDOS do tenant — linhas com número definitivo. Rascunhos (carrinho da loja, venda pausada no PDV, orçamento, cart de WhatsApp) ficam fora por padrão; passe status=rascunho para trazê-los. Filtros por status, canal, oportunidade, contato, telefone e busca textual (número/nome). Paginação via page/page_size (máx 50).","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string","pattern":"^[a-z_]{1,32}$"},"in":"query","name":"canal","required":false,"description":"Canal de venda (canal_venda): web, pdv, marketplace. Aceita o valor legado de `canal` (ex.: site)."},{"schema":{"type":"string"},"in":"query","name":"marketplace_provider","required":false,"description":"Recorta os pedidos de marketplace por canal (ex.: mercado_livre)"},{"schema":{"type":"string","enum":["true"]},"in":"query","name":"loja_conectada","required":false,"description":"Só os pedidos ligados ao canal (sales_channel_id preenchido): deixa de fora os da loja desconectada"},{"schema":{"type":"string","enum":["site","whatsapp","manual","crm","ia_conversacional","marketplace","instagram","orcamento"]},"in":"query","name":"origem","required":false,"description":"Origem do pedido. \"orcamento\" traz a fila de orçamentos pedidos pelo cliente na loja (combinar com status=rascunho)"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"oportunidade_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"contato_id","required":false},{"schema":{"type":"string"},"in":"query","name":"cliente_telefone","required":false},{"schema":{"type":"string"},"in":"query","name":"busca","required":false,"description":"Busca por número ou nome do cliente"},{"schema":{"type":"string"},"in":"query","name":"data_entrega","required":false,"description":"Filtra por data de agendamento (YYYY-MM-DD): pedidos com agendamento_data = valor"},{"schema":{"type":"string","enum":["envio","retirada"]},"in":"query","name":"tipo_entrega","required":false,"description":"Filtra por tipo de entrega"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"data_de","required":false,"description":"Pedidos criados a partir deste dia (AAAA-MM-DD, dia de São Paulo, inclusive)"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"in":"query","name":"data_ate","required":false,"description":"Pedidos criados até o fim deste dia (AAAA-MM-DD, dia de São Paulo, inclusive)"},{"schema":{"type":"string","enum":["created_at_desc","created_at_asc","total_centavos_desc","total_centavos_asc"],"default":"created_at_desc"},"in":"query","name":"sort","required":false,"description":"Ordem da lista: created_at_desc (padrão), created_at_asc, total_centavos_desc, total_centavos_asc"},{"schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false},{"schema":{"type":"string","default":"20"},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}}},"/pedidos/metricas":{"get":{"summary":"Métricas de pedidos por período","tags":["OMS - Pedidos"],"description":"Retorna métricas comparativas entre o período atual e o anterior (receita, ticket médio, pedidos por status, variação percentual). Parâmetro dias (1-365, default 7).","parameters":[{"schema":{"type":"string","default":"7"},"in":"query","name":"dias","required":false,"description":"Número de dias do período (1-365)"},{"schema":{"type":"string","pattern":"^[a-z_]{1,32}$"},"in":"query","name":"canal","required":false,"description":"Mesmo filtro de canal da listagem (aba da tela)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/contagem-por-canal":{"get":{"summary":"Quantidade de pedidos por canal (abas da lista)","tags":["OMS - Pedidos"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"}}}}}}}},"/pedidos/abandonados":{"get":{"summary":"Listar checkouts abandonados","tags":["OMS - Pedidos"],"description":"Retorna pedidos rascunho com status_carrinho=abandonado (checkouts não concluídos). Exclui PDV e carrinhos R$0. Filtro por nome/email/telefone. Cada linha traz `etapa` (até onde o cliente foi): carrinho, contato, entrega ou pagamento_recusado.","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Busca por nome, email ou telefone"},{"schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false},{"schema":{"type":"string","default":"50"},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}}},"/pedidos/{id}":{"get":{"summary":"Detalhe do pedido","tags":["OMS - Pedidos"],"description":"Retorna pedido completo com itens, timeline de status e dados do cliente (incluindo endereços).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir pedido","tags":["OMS - Pedidos"],"description":"Exclui permanentemente um pedido. Apenas pedidos pendentes, rascunho ou cancelados podem ser excluídos. Pedidos pagos ou em andamento não podem ser removidos.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/insights":{"get":{"summary":"Insights de conversão e risco do pedido","tags":["OMS - Pedidos"],"description":"Retorna dados de conversão (visitante, sessão de compra, atribuição UTM, tempo de conversão) e a análise antifraude do pedido pelo motor Rekta Shield (score 0-100, nível, recomendação e os sinais que produziram o score).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/{id}/envios":{"get":{"summary":"Listar envios do pedido","tags":["OMS - Pedidos"],"description":"Retorna os envios (por local de despacho) do pedido, com status, frete, rastreio e itens de cada envio. Pedidos sem roteamento Multi-CD retornam lista vazia.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/{id}/envios/{envioId}":{"patch":{"summary":"Atualizar envio do pedido","tags":["OMS - Pedidos"],"description":"Atualiza status/rastreio/etiqueta de um envio (Multi-CD). Status aceitos: preparando, despachado. Ao marcar status=despachado vindo de pendente/preparando, dá baixa de estoque apenas dos itens daquele envio (guard atômico contra baixa dupla).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"tracking_code":{"type":"string","nullable":true},"etiqueta_url":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"envioId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/status":{"patch":{"summary":"Atualizar status do pedido","tags":["OMS - Pedidos"],"description":"Atualiza o status do pedido, registra log e executa operações de estoque (reserva/baixa/cancelamento) e envia emails de transição (pedido enviado, etc.).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"Novo status: pendente, pago, confirmado, preparando, enviado, entregue, cancelado, reembolsado"},"descricao":{"type":"string","nullable":true},"forma_pagamento":{"type":"string","nullable":true}},"required":["status"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/rastreio":{"patch":{"summary":"Informar rastreio","tags":["OMS - Pedidos"],"description":"Grava o código de rastreio, a transportadora e o link para o cliente. transportadora_id: id de GET /transportadoras-rastreio (da loja ou do catálogo), e o link se monta pelo modelo. Sem id: transportadora_nome e rastreio_url avulsos. Só o código: Correios quando o código é dos Correios. A edição manual passa a valer sobre a sincronização automática.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rastreio":{"type":"string","maxLength":120},"transportadora_id":{"type":["string","null"],"maxLength":80},"transportadora_nome":{"type":["string","null"],"maxLength":200},"rastreio_url":{"type":["string","null"],"maxLength":2100}},"required":["rastreio"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"rastreio":{"type":"string"},"rastreio_transportadora":{"type":["null","string"]},"rastreio_url":{"type":["null","string"]}}}}}}}}},"/pedidos/{id}/tags":{"patch":{"summary":"Atualizar tags do pedido","tags":["OMS - Pedidos"],"description":"Define as tags do pedido (máximo 20, lowercase, até 40 caracteres cada). Remove duplicatas automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tags":{"type":"array","items":{"type":"string"},"maxItems":20}},"required":["tags"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tags":{"type":"array","items":{"type":"string"}}}}}}}}}},"/pedidos/{id}/cliente":{"patch":{"summary":"Atualizar dados do cliente no pedido","tags":["OMS - Pedidos"],"description":"Atualiza nome, email, telefone e/ou CPF do cliente no pedido. Sincroniza com busca Typesense.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cliente_nome":{"type":"string"},"cliente_email":{"type":"string","nullable":true},"cliente_telefone":{"type":"string","nullable":true},"cliente_cpf":{"type":"string","nullable":true}},"required":["cliente_nome"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/etiqueta":{"post":{"summary":"Gerar etiqueta de envio (Melhor Envio)","tags":["OMS - Pedidos"],"description":"Gera etiqueta no Melhor Envio, debita saldo do tenant. Requer role owner/manager/super_admin. Requer conexão Melhor Envio ativa e local de estoque cadastrado. Guard contra duplicidade via frete_etiqueta_id.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"service_id":{"type":"integer","nullable":true,"description":"ID do serviço Melhor Envio (override)"},"local_retirada_id":{"type":"string","format":"uuid","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"sucesso":{"type":"boolean"},"tracking":{"type":"string"},"pdf_url":{"type":"string"},"shipment_id":{"type":"string"}}}}}}}},"get":{"summary":"Obter PDF da etiqueta de envio","tags":["OMS - Pedidos"],"description":"Retorna URL do PDF da etiqueta. Se não está salvo, tenta reimprimir via Melhor Envio.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pdf_url":{"type":"string"},"recuperado":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/etiqueta/cancelar":{"post":{"summary":"Cancelar etiqueta de envio","tags":["OMS - Pedidos"],"description":"Cancela etiqueta no Melhor Envio (devolve saldo). Só funciona se a encomenda ainda não foi postada. Requer role owner/manager/super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sucesso":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/notificar":{"post":{"summary":"Reenviar e-mail de confirmação ao cliente","tags":["OMS - Pedidos"],"description":"Reenvia o e-mail de confirmação do pedido ao cliente. Usa branding do tenant.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/sincronizar-canal":{"post":{"summary":"Consultar o canal de venda sobre este pedido agora","tags":["OMS - Pedidos"],"description":"Relê o pedido no marketplace de origem e aplica o que vier (status, envio, baixa de estoque). Responde se algo mudou de fato. Requer papel manager ou acima.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"executado":{"type":"boolean"},"em_andamento":{"type":"boolean"},"enfileirado":{"type":"boolean"},"mudou":{"type":"boolean"},"provider":{"type":"string"},"order_id":{"type":"string","nullable":true},"status_antes":{"type":"string"},"status_depois":{"type":"string"},"parado_ha_horas":{"type":"number"},"sincronizado_em":{"type":"string"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/pedidos/{id}/refund":{"post":{"summary":"Reembolsar pagamento (total ou parcial)","tags":["OMS - Pedidos"],"description":"Dispara reembolso no gateway que processou o pagamento OU devolve o valor como créditos na loja (vale-troca). Detecta o provider automaticamente. Refund parcial via amount_centavos. destino=creditos requer cliente vinculado e o app Cashback ativo. Requer role owner/manager/super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"amount_centavos":{"type":"integer","minimum":1,"nullable":true},"motivo":{"type":"string","nullable":true},"destino":{"type":"string","enum":["gateway","creditos"],"nullable":true},"idempotency_key":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"destino":{"type":"string","enum":["gateway","creditos"]},"gateway":{"type":"string"},"refund_id":{"type":"string","nullable":true},"amount_centavos":{"type":"integer"},"tipo":{"type":"string","enum":["total","parcial"]},"valor_creditos_centavos":{"type":"integer"},"incentivo_percent":{"type":"number"}}}}}}}}},"/pedidos/webhook/pagarme":{"post":{"summary":"Webhook Pagar.me (Varejo Pay)","tags":["OMS - Pedidos"],"description":"Recebe notificações de pagamento do Pagar.me (Varejo Pay e third-party). Valida assinatura HMAC, processa confirmação/recusa de pagamento e atualiza status do pedido. Rate-limited: 30 req/min.","responses":{"200":{"description":"Default Response"}}}},"/pedidos/interno":{"post":{"summary":"Criar pedido interno (service-to-service)","tags":["OMS - Pedidos"],"description":"Cria pedido via chamada interna (CRM/IA). Autenticação via header X-Internal-Key. Pode gerar cobrança Pix opcionalmente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","format":"uuid"},"oportunidade_id":{"type":"string","format":"uuid"},"contato_id":{"type":"string","format":"uuid"},"canal":{"type":"string"},"cliente_nome":{"type":"string"},"cliente_telefone":{"type":"string","nullable":true},"cliente_email":{"type":"string","nullable":true},"itens":{"type":"array","items":{"type":"object","additionalProperties":true},"minItems":1},"gerar_cobranca":{"type":"boolean","default":false}},"required":["account_id","oportunidade_id","contato_id","canal","cliente_nome","itens"]}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"numero":{"type":"string"},"total_centavos":{"type":"integer"},"payment_url":{"type":"string","nullable":true}}}}}}}}},"/pedidos/webhook/gateway/{accountId}":{"post":{"summary":"Webhook gateway third-party por tenant","tags":["OMS - Pedidos"],"description":"Recebe notificações de pagamento de gateways configurados pelo tenant (Pagar.me conta própria). Valida assinatura HMAC com secret do gateway. Idempotente via gateway_webhook_events.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/pedidos/{id}/recomprar":{"post":{"summary":"Recomprar: transforma um pedido anterior em carrinho","tags":["OMS - Pedidos"],"description":"Revalida os itens de um pedido anterior contra o catálogo atual (produto ativo, catálogo da unidade B2B, variação viva, preço e estoque), adiciona ao carrinho da sessão com o PREÇO DE HOJE e devolve o que entrou e o que ficou de fora, com motivo por item. Exige o comprador dono do pedido (ou, em pedido de atacado, contato da unidade B2B).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"account_id":{"type":"string","format":"uuid"},"session_token":{"type":"string","minLength":1}},"required":["account_id","session_token"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/pedidos/pix-qrcode":{"get":{"summary":"QR Code Pix em PNG (para e-mail)","tags":["OMS - Pedidos"],"description":"Renderiza o BR Code assinado como imagem PNG. Endpoint público, sem JWT: o par (c, s) é gerado pelo próprio serviço ao montar o e-mail.","parameters":[{"schema":{"type":"string"},"in":"query","name":"c","required":true},{"schema":{"type":"string"},"in":"query","name":"s","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/public/pedidos/track":{"get":{"summary":"Rastreamento público do pedido (cliente)","tags":["OMS - Pedidos"],"description":"Retorna dados do pedido para a página pública de acompanhamento. Valida identidade por email. Inclui itens, timeline, dados da loja e logo. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string"},"in":"query","name":"numero","required":true},{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true},{"schema":{"type":"string","format":"uuid","nullable":true},"in":"query","name":"account_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/pedidos/pagamento":{"get":{"summary":"Consultar status de pagamento público","tags":["OMS - Pedidos"],"description":"Consulta o status de pagamento de um pedido pendente no gateway (Pix/boleto). Retorna QR code Pix atualizado ou status da cobrança. Validação por email + escopo de loja. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string"},"in":"query","name":"numero","required":true},{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true},{"schema":{"type":"string","format":"uuid","nullable":true},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","nullable":true},"in":"query","name":"tenant_slug","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/cleanup":{"post":{"summary":"Cleanup de pedidos pendentes expirados","tags":["OMS - Pedidos"],"description":"Cancela pedidos pendentes com mais de 24h (timeout de pagamento). Libera reservas de estoque e envia email de pagamento expirado. Autenticação via X-Internal-Key (CRON interno).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cancelados":{"type":"integer"},"total_expirados":{"type":"integer"}}}}}}}}},"/public/pedidos/track/status":{"get":{"summary":"Status do pagamento do pedido (cliente)","tags":["OMS - Pedidos"],"description":"Status e prazo do pagamento para as telas que esperam o Pix. Valida identidade por número + e-mail, como /public/pedidos/track. Com Pix pendente, confere o pagamento no gateway em segundo plano. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string"},"in":"query","name":"numero","required":true},{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true},{"schema":{"type":"string","format":"uuid","nullable":true},"in":"query","name":"account_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/frete/config":{"get":{"summary":"Listar configurações de frete","tags":["Logística - Frete (Legacy)"],"description":"Retorna todas as configurações de frete do tenant (local, propria, retirada, melhor_envio, motoboy). Ordenadas por data de criação.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"tipo":{"type":"string","enum":["local","propria","retirada","melhor_envio","correios","motoboy","entrega_propria","transportadora"]},"config":{"type":"object","additionalProperties":true},"ativo":{"type":"boolean"},"created_at":{"type":"string","format":"date-time"}}}}}}}}},"post":{"summary":"Criar ou atualizar configuração de frete","tags":["Logística - Frete (Legacy)"],"description":"Cria ou atualiza uma configuração de frete. Tipos únicos (melhor_envio, retirada, correios) fazem upsert; tipos múltiplos (local, propria) sempre inserem. Se \"id\" informado, atualiza diretamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo","config","ativo"],"properties":{"id":{"type":"string","format":"uuid","description":"Se informado, atualiza por ID"},"tipo":{"type":"string","enum":["local","propria","retirada","melhor_envio","correios","motoboy","entrega_propria","transportadora"]},"nome":{"type":"string"},"config":{"type":"object","description":"Configuração específica do tipo (faixas CEP, preço fixo, etc.)"},"ativo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string","format":"uuid","description":"Presente apenas em inserções"}}}}}}}}},"/frete/config/{id}":{"delete":{"summary":"Remover configuração de frete","tags":["Logística - Frete (Legacy)"],"description":"Remove permanentemente uma configuração de frete pelo ID.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/carrinhos":{"post":{"summary":"Criar carrinho conversacional","tags":["Checkout - Carrinhos"],"description":"Cria um carrinho rascunho vinculado a uma conversa do Connect. Também cria um pedido rascunho vinculado (best-effort). Não disponível para vertical imobiliária.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"conversa_id":{"type":"string","format":"uuid"},"lead_id":{"type":"string","format":"uuid","description":"ID do lead/oportunidade (opcional)"}},"required":["conversa_id"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Listar carrinhos","tags":["Checkout - Carrinhos"],"description":"Lista carrinhos do tenant com filtros por conversa_id, contato_id e status.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"conversa_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"contato_id","required":false},{"schema":{"type":"string","enum":["rascunho","enviado","confirmado","cancelado"]},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/carrinhos/{id}":{"get":{"summary":"Detalhe do carrinho com itens e serviços","tags":["Checkout - Carrinhos"],"description":"Retorna carrinho pelo ID com itens e serviços vinculados a cada item.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"status":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"patch":{"summary":"Atualizar desconto, pagamento e observação","tags":["Checkout - Carrinhos"],"description":"Atualiza desconto_percentual, forma_pagamento, parcelas e/ou observacao do carrinho. Desconto acima de 15% requer role manager/owner/super_admin. Sincroniza com pedido vinculado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"desconto_percentual":{"type":"number","minimum":0,"maximum":100},"forma_pagamento":{"type":"string","enum":["pix","boleto","cartao","crediario"]},"parcelas":{"type":"integer","minimum":1},"observacao":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/carrinhos/{id}/cancelar":{"patch":{"summary":"Cancelar carrinho","tags":["Checkout - Carrinhos"],"description":"Cancela o carrinho e o pedido rascunho vinculado. Registra log de status.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/carrinhos/{id}/itens":{"post":{"summary":"Adicionar item ao carrinho","tags":["Checkout - Carrinhos"],"description":"Adiciona produto ao carrinho ou incrementa quantidade se já existe. Busca serviços vinculados ao produto automaticamente. Valida estoque e produto ativo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":"string","format":"uuid","nullable":true},"quantidade":{"type":"number","minimum":1,"default":1}},"required":["produto_id"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/carrinhos/{id}/itens/{itemId}":{"patch":{"summary":"Atualizar quantidade do item","tags":["Checkout - Carrinhos"],"description":"Atualiza a quantidade de um item do carrinho. Recalcula serviços percentuais e totais.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"quantidade":{"type":"number","minimum":0.01}},"required":["quantidade"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}},"delete":{"summary":"Remover item do carrinho","tags":["Checkout - Carrinhos"],"description":"Remove um item do carrinho e recalcula os totais.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/carrinhos/{id}/itens/{itemId}/servicos/{servicoId}":{"patch":{"summary":"Ativar/desativar serviço do item","tags":["Checkout - Carrinhos"],"description":"Toggle do flag ativo de um serviço vinculado a um item do carrinho. Recalcula totais.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"}},"required":["ativo"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"servicoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/carrinhos/{id}/enviar":{"post":{"summary":"Enviar resumo do carrinho ao cliente","tags":["Checkout - Carrinhos"],"description":"Marca o carrinho como enviado e retorna mensagem formatada para envio via WhatsApp ao cliente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"mensagem":{"type":"string"}}}}}}}}},"/carrinhos/{id}/confirmar":{"post":{"summary":"Confirmar carrinho e criar pedido","tags":["Checkout - Carrinhos"],"description":"Confirma o carrinho, valida produtos/estoque, cria ou atualiza o pedido vinculado (rascunho para pendente), copia itens e vincula à oportunidade. Retorna divergências de preço se houver.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"numero":{"type":"string"},"precos_divergentes":{"type":"array","items":{"type":"object","additionalProperties":true},"nullable":true}}}}}}}}},"/pedidos/rascunho/contexto":{"get":{"summary":"Obter ou criar rascunho por contexto","tags":["OMS - Draft Orders"],"description":"Busca ou cria um pedido rascunho ativo (Shopify Draft Order pattern) a partir de conversa_id ou session_token. Retorna pedido com itens. Multi-origem: conversa (Connect) ou session (Loja anônima).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"conversa_id","required":false,"description":"ID da conversa (WhatsApp/chat)"},{"schema":{"type":"string"},"in":"query","name":"session_token","required":false,"description":"Token de sessão da loja virtual"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"lead_id","required":false,"description":"ID do lead/oportunidade (opcional)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"total_centavos":{"type":"integer"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/pedidos/rascunho/{id}":{"get":{"summary":"Detalhe do rascunho com itens","tags":["OMS - Draft Orders"],"description":"Retorna um pedido rascunho pelo ID, incluindo todos os itens. Usado pelo drawer do Connect.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"status":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"patch":{"summary":"Atualizar dados do rascunho","tags":["OMS - Draft Orders"],"description":"Atualiza forma_pagamento, parcelas, desconto_percentual e/ou observacao do rascunho. Desconto acima de 15% requer role manager/owner/super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"desconto_percentual":{"type":"number","minimum":0,"maximum":100},"forma_pagamento":{"type":"string","enum":["pix","boleto","cartao","crediario"]},"parcelas":{"type":"integer","minimum":1},"observacao":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/rascunho/{id}/orcamento":{"get":{"summary":"Dados do orçamento em PDF","tags":["OMS - Draft Orders"],"description":"Junta empresa (razão social, CNPJ, IE, endereço, contato e logotipo), cliente, vendedor, itens com código, totais e condição de pagamento do rascunho, para o painel gerar o orçamento em PDF.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/oportunidades/{id}/orcamento":{"get":{"summary":"Dados do orçamento em PDF de uma oportunidade","tags":["CRM - Oportunidades"],"description":"Junta empresa, contato, vendedor, produtos da oportunidade com código e totais, para o painel gerar o orçamento em PDF pelo CRM.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/rascunho":{"get":{"summary":"Listar rascunhos ativos","tags":["OMS - Draft Orders"],"description":"Retorna rascunhos ativos (status=rascunho, status_carrinho=ativo) filtrados por conversa, contato ou cliente. O filtro cliente_id mostra o carrinho ativo na loja em tempo real para o CRM.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"conversa_id","required":false,"description":"Rascunho montado nessa conversa"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"contato_id","required":false,"description":"Rascunhos de qualquer conversa do contato CRM"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"cliente_id","required":false,"description":"Rascunhos do cliente (Customer 360)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/pedidos/rascunho/{id}/absorver":{"post":{"summary":"Absorver rascunho da loja para conversa","tags":["OMS - Draft Orders"],"description":"Atendente \"absorve\" um rascunho da loja virtual para a conversa atual, vinculando conversa_id e contato_id. A partir daí qualquer ação do drawer afeta o mesmo pedido. Padrão Shopify Inbox.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"conversa_id":{"type":"string","format":"uuid"}},"required":["conversa_id"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"pedido_id":{"type":"string"},"conversa_id":{"type":"string"}}}}}}}}},"/pedidos/rascunho/{id}/itens":{"post":{"summary":"Adicionar item ao rascunho","tags":["OMS - Draft Orders"],"description":"Adiciona um produto ao rascunho ou incrementa quantidade se já existe (mesmo produto+variacao). Valida estoque e produto ativo. Recalcula totais automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":"string","format":"uuid","nullable":true},"quantidade":{"type":"number","minimum":1,"default":1}},"required":["produto_id"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/rascunho/kit-da-capa/{produtoId}":{"get":{"summary":"Kit de que o produto é capa (Monte seu Kit)","tags":["OMS - Draft Orders"],"description":"Para o carrinho do atendente: se o produto é capa de um kit publicado do app Monte seu Kit, devolve a definição e os elegíveis para montar. 404 quando não é capa. 422 kit_indisponivel quando o kit não fecha com o catálogo atual.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/rascunho/{id}/kit":{"post":{"summary":"Adicionar kit montado ao rascunho (Monte seu Kit)","tags":["OMS - Draft Orders"],"description":"Revalida a escolha contra o kit publicado, trava o preço por item no servidor e insere as linhas do kit no rascunho. Erros 422: kit_indisponivel, kit_min_itens, kit_max_itens, produto_nao_elegivel, produto_sem_estoque, produto_nao_compravel.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["kit_slug","itens"],"properties":{"kit_slug":{"type":"string"},"itens":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["produto_id"],"additionalProperties":true,"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"]},"quantidade":{"type":"integer","minimum":1,"maximum":999}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"itens":{"type":"integer"}}}}}}}}},"/pedidos/rascunho/{id}/itens/{itemId}":{"patch":{"summary":"Atualizar quantidade de item","tags":["OMS - Draft Orders"],"description":"Atualiza a quantidade de um item do rascunho. Recalcula subtotal do item e totais do pedido.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"quantidade":{"type":"number","minimum":0.01}},"required":["quantidade"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}},"delete":{"summary":"Remover item do rascunho","tags":["OMS - Draft Orders"],"description":"Remove um item do rascunho e recalcula os totais do pedido.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/rascunho/{id}/cancelar":{"post":{"summary":"Cancelar (descartar) rascunho","tags":["OMS - Draft Orders"],"description":"Descarta o rascunho marcando status como cancelado e status_carrinho como descartado. Registra log de status.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pedidos/rascunho/{id}/checkout":{"post":{"summary":"Promover rascunho para pedido pendente","tags":["OMS - Draft Orders"],"description":"Confirma o rascunho promovendo para status pendente (aguardando pagamento). Valida produtos ativos, estoque, forma de pagamento e gera número RKT-XXXXXX. Equivalente ao \"confirmar pedido\" do drawer Connect.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"numero":{"type":"string"},"precos_divergentes":{"type":"array","items":{"type":"object","properties":{"nome":{"type":"string"},"carrinho":{"type":"integer"},"atual":{"type":"integer"}}},"nullable":true}}}}}}}}},"/public/checkout/{id}":{"get":{"summary":"Checkout público via link assinado","tags":["OMS - Draft Orders"],"description":"Retorna pedido rascunho, itens, dados do tenant e endereços do cliente para pré-preencher o checkout. Autenticação via token HMAC na query. Padrão Shopify Send Invoice.","parameters":[{"schema":{"type":"string"},"in":"query","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pedido":{"type":"object","additionalProperties":true},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"account":{"type":"object","additionalProperties":true},"cliente":{"type":"object","additionalProperties":true,"nullable":true},"enderecos":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/public/checkout/{id}/finalizar":{"post":{"summary":"Finalizar checkout público","tags":["OMS - Draft Orders"],"description":"Atualiza rascunho com endereço, frete, forma de pagamento e promove para status pendente. Gera número RKT-XXXXXX. Autenticação via token HMAC.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cliente_nome":{"type":"string"},"cliente_telefone":{"type":"string"},"cliente_email":{"type":"string","nullable":true},"cliente_cpf":{"type":"string","nullable":true},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero_end":{"type":"string","nullable":true},"complemento":{"type":"string","nullable":true},"bairro":{"type":"string","nullable":true},"cidade":{"type":"string"},"uf":{"type":"string"},"forma_pagamento":{"type":"string"},"parcelas":{"type":"integer","default":1},"frete_centavos":{"type":"integer","nullable":true},"frete_tipo":{"type":"string","nullable":true},"frete_prazo_dias":{"type":"integer","nullable":true},"tipo_entrega":{"type":"string","enum":["envio","retirada"],"nullable":true},"local_retirada_id":{"type":"string","format":"uuid","nullable":true}},"required":["cliente_nome","cliente_telefone","cep","logradouro","cidade","uf","forma_pagamento"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"numero":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/pedidos/rascunho/{id}/gerar-link-checkout":{"post":{"summary":"Gerar link de checkout para envio ao cliente","tags":["OMS - Draft Orders"],"description":"Gera URL pública do checkout com session_token para o atendente/IA enviar ao cliente via WhatsApp. Auto-resolve cliente_id a partir do contato. Emite evento checkout_invoice_sent. Padrão Shopify Send Invoice.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"session_token":{"type":"string"},"pedido_id":{"type":"string"}}}}}}}}},"/pedidos/rascunho/{id}/enviar":{"post":{"summary":"Gerar resumo formatado do rascunho","tags":["OMS - Draft Orders"],"description":"Retorna mensagem formatada do rascunho para envio ao cliente via WhatsApp. Não altera status do pedido.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"mensagem":{"type":"string"}}}}}}}}},"/rekta-pay/faixas":{"get":{"summary":"Listar faixas de taxa (público)","tags":["Pagamentos - Varejo Pay"],"description":"Retorna faixas de taxa do Varejo Pay ordenadas por ordem. Usado na calculadora pública.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/rekta-pay/config":{"get":{"summary":"Consultar configuração Varejo Pay","tags":["Pagamentos - Varejo Pay"],"description":"Retorna config do tenant (parcelas sem juros, ativo, prazo de recebimento).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Criar ou atualizar configuração Varejo Pay","tags":["Pagamentos - Varejo Pay"],"description":"Upsert da configuração. Exige 2FA para desativar. Atualiza antecipação no Pagar.me quando prazo muda.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parcelas_sem_juros":{"type":"number"},"ativo":{"type":"boolean"},"prazo_recebimento":{"type":"string","enum":["d2","d30"]},"confirmacao_2fa":{"type":"string","description":"Token 2FA (obrigatório para desativar)"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/saldo":{"get":{"summary":"Consultar saldo real","tags":["Pagamentos - Varejo Pay"],"description":"Retorna saldo disponível e a liberar via API Pagar.me. Fallback para cache local se API falhar.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"disponivel":{"type":"number"},"a_liberar":{"type":"number"},"total":{"type":"number"},"fonte":{"type":"string"}}}}}}}}},"/rekta-pay/dashboard":{"get":{"summary":"Dashboard financeiro Varejo Pay","tags":["Pagamentos - Varejo Pay"],"description":"Retorna saldo real (API + fallback cache), faturamento do mês, faixa de taxa atual, config e status KYC.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/transacoes":{"get":{"summary":"Listar transações (extrato paginado)","tags":["Pagamentos - Varejo Pay"],"description":"Extrato com filtros por status, método, período e busca (nome/documento/pedido_id). Paginação cursor.","parameters":[{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false,"description":"CSV: pendente,disponivel,sacada,estornada"},{"schema":{"type":"string"},"in":"query","name":"metodo","required":false,"description":"CSV: credito,debito,pix,boleto"},{"schema":{"type":"string"},"in":"query","name":"desde","required":false,"description":"YYYY-MM-DD"},{"schema":{"type":"string"},"in":"query","name":"ate","required":false,"description":"YYYY-MM-DD"},{"schema":{"type":"string"},"in":"query","name":"busca","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"total_pages":{"type":"number"}}}}}}}}},"/rekta-pay/transacoes/export":{"get":{"summary":"Exportar extrato (CSV ou OFX)","tags":["Pagamentos - Varejo Pay"],"description":"Exporta transações com mesmos filtros da listagem em formato CSV (BOM UTF-8 para Excel) ou OFX 1.0.3 (SGML).","parameters":[{"schema":{"type":"string","enum":["csv","ofx"]},"in":"query","name":"formato","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"metodo","required":false},{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false},{"schema":{"type":"string"},"in":"query","name":"busca","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/transacoes/{id}":{"get":{"summary":"Detalhe de uma transação","tags":["Pagamentos - Varejo Pay"],"description":"Retorna transação com pedido vinculado.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/saques":{"post":{"summary":"Solicitar saque","tags":["Pagamentos - Varejo Pay"],"description":"Cria transferência no Pagar.me após validar saldo real. Máximo R$ 50.000 por saque. Snapshot dos dados bancários.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["valor_centavos"],"properties":{"valor_centavos":{"type":"number","description":"Valor em centavos (max 5000000)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Listar saques","tags":["Pagamentos - Varejo Pay"],"description":"Histórico de saques com paginação.","parameters":[{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"number"},"page":{"type":"number"},"limit":{"type":"number"},"total_pages":{"type":"number"}}}}}}}}},"/rekta-pay/antecipacao/simular":{"get":{"summary":"Simular antecipação","tags":["Pagamentos - Varejo Pay"],"description":"Consulta limites de antecipação no Pagar.me para uma data de pagamento.","parameters":[{"schema":{"type":"string"},"in":"query","name":"payment_date","required":false,"description":"Data de pagamento YYYY-MM-DD (default: D+1)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/antecipacao":{"post":{"summary":"Solicitar antecipação","tags":["Pagamentos - Varejo Pay"],"description":"Cria antecipação em lote no Pagar.me. Apenas owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["amount_centavos"],"properties":{"amount_centavos":{"type":"number"},"payment_date":{"type":"string","description":"YYYY-MM-DD (default: D+1)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Histórico de antecipações","tags":["Pagamentos - Varejo Pay"],"description":"Lista antecipações do recipient no Pagar.me.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"paging":{"type":"object","additionalProperties":true}}}}}}}}},"/rekta-pay/reembolso":{"post":{"summary":"Solicitar reembolso","tags":["Pagamentos - Varejo Pay"],"description":"Estorna cobrança no Pagar.me (total ou parcial). Idempotente por charge_id+valor. Registra transação negativa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_id"],"properties":{"pedido_id":{"type":"string","format":"uuid"},"valor_centavos":{"type":"number","description":"Valor parcial (omitir para estorno total)"},"motivo":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"sucesso":{"type":"boolean"},"valor_estornado":{"type":"number"},"status":{"type":"string"}}}}}}}}},"/rekta-pay/transferencias":{"get":{"summary":"Listar transferências (sync com Pagar.me)","tags":["Pagamentos - Varejo Pay"],"description":"Consulta transferências na API Pagar.me e sincroniza status dos saques locais.","parameters":[{"schema":{"type":"string"},"in":"query","name":"page","required":false},{"schema":{"type":"string"},"in":"query","name":"size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"number"},"page":{"type":"number"}}}}}}}}},"/rekta-pay/dados-bancarios":{"post":{"summary":"Cadastrar dados bancários + criar recipient","tags":["Pagamentos - Varejo Pay"],"description":"Cria recipient no Pagar.me (formato V5) com dados bancários, empresa e representante legal. Compliance PLD/AML com dados fiscais reais. Exige 2FA para edição.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["banco","agencia","conta","tipo_conta","titular","documento","empresa_email","empresa_telefone_ddd","empresa_telefone_numero","empresa_cep","empresa_logradouro","empresa_numero","empresa_bairro","empresa_cidade","empresa_uf","representante_nome","representante_email","representante_cpf","representante_nascimento","representante_telefone_ddd","representante_telefone_numero"],"properties":{"banco":{"type":"string"},"agencia":{"type":"string"},"conta":{"type":"string"},"tipo_conta":{"type":"string","enum":["corrente","poupanca"]},"titular":{"type":"string"},"documento":{"type":"string"},"confirmacao_2fa":{"type":"string","description":"Token 2FA (obrigatório para edição)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"recipient_id":{"type":"string"},"kyc_url":{"type":"string","nullable":true},"message":{"type":"string"}}}}}}}},"get":{"summary":"Consultar dados bancários e KYC","tags":["Pagamentos - Varejo Pay"],"description":"Retorna dados bancários salvos, recipient_id e status KYC (atualizado via API Pagar.me se possível).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"dados_bancarios":{"type":"object","nullable":true,"additionalProperties":true},"recipient_id":{"type":"string","nullable":true},"kyc_status":{"type":"string"}}}}}}}}},"/rekta-pay/kyc-link":{"get":{"summary":"Obter link KYC do Pagar.me","tags":["Pagamentos - Varejo Pay"],"description":"Gera link de verificação KYC para o recipient do tenant.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}}}}},"/rekta-pay/admin/faixas":{"post":{"summary":"Criar ou atualizar faixa de taxa (admin)","tags":["Pagamentos - Varejo Pay"],"description":"CRUD de faixas de taxa Varejo Pay. Apenas super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","ordem"],"properties":{"id":{"type":"string","format":"uuid","description":"Se informado, faz update"},"nome":{"type":"string"},"ordem":{"type":"number"},"faturamento_min":{"type":"number"},"faturamento_max":{"type":"number","nullable":true},"taxa_pix":{"type":"number"},"taxa_boleto_centavos":{"type":"number"},"taxa_debito":{"type":"number"},"taxa_credito_1x":{"type":"number"},"taxa_credito_2_6x":{"type":"number"},"taxa_credito_7_12x":{"type":"number"},"antecipacao_am_bps":{"type":"number"},"planos":{"type":"array","items":{"type":"string"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/admin/taxa-especial":{"get":{"summary":"Listar lojas com taxa especial (admin)","tags":["Pagamentos - Varejo Pay"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Definir ou remover taxa especial de uma loja (admin)","tags":["Pagamentos - Varejo Pay"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id"],"properties":{"account_id":{"type":"string"},"faixa_id":{"type":"string","nullable":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/admin/lojas":{"get":{"summary":"Buscar lojas pelo nome (admin)","tags":["Pagamentos - Varejo Pay"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/rekta-pay/admin/faixas/{id}":{"delete":{"summary":"Excluir faixa de taxa (admin)","tags":["Pagamentos - Varejo Pay"],"description":"Remove faixa de taxa. Apenas super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/rekta-pay/cadastro/rascunho":{"get":{"summary":"Consultar rascunho do cadastro","tags":["Pagamentos - Varejo Pay"],"description":"Retorna o rascunho do wizard de cadastro Varejo Pay (save-as-draft).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"additionalProperties":true}}}}}},"post":{"summary":"Salvar rascunho do cadastro","tags":["Pagamentos - Varejo Pay"],"description":"Upsert do rascunho do wizard (debounce ~800ms no frontend).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["payload"],"properties":{"payload":{"type":"object","additionalProperties":true},"ultimo_step":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}},"delete":{"summary":"Apagar rascunho do cadastro","tags":["Pagamentos - Varejo Pay"],"description":"Remove o rascunho após cadastro finalizado com sucesso.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/rekta-pay/lookup-cnpj":{"get":{"summary":"Consultar CNPJ na BrasilAPI","tags":["Pagamentos - Varejo Pay"],"description":"Proxy para BrasilAPI que retorna dados cadastrais do CNPJ normalizados para o wizard.","parameters":[{"schema":{"type":"string"},"in":"query","name":"cnpj","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/validar-chave-pix":{"post":{"summary":"Validar chave Pix","tags":["Pagamentos - Varejo Pay"],"description":"Validação server-side do formato da chave Pix (CPF, CNPJ, e-mail, telefone, aleatória).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo","chave"],"properties":{"tipo":{"type":"string","enum":["cpf","cnpj","email","telefone","aleatoria"]},"chave":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"tipo":{"type":"string"},"chave":{"type":"string"}}}}}}}}},"/rekta-pay/documentos":{"post":{"summary":"Registrar documento KYC","tags":["Pagamentos - Varejo Pay"],"description":"Registra documento pendente e retorna signed upload URL do Supabase Storage (bucket kyc-docs). Tipos: cartao_cnpj, ccmei, contrato_social, rg_cnh, selfie, comprovante_endereco. Max 10MB.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo","file_name","mime_type","tamanho_bytes"],"properties":{"tipo":{"type":"string","enum":["cartao_cnpj","ccmei","contrato_social","rg_cnh","selfie","comprovante_endereco","outro"]},"file_name":{"type":"string"},"mime_type":{"type":"string","enum":["application/pdf","image/png","image/jpeg","image/webp"]},"tamanho_bytes":{"type":"number"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"signed_upload_url":{"type":"string"},"token":{"type":"string"}}}}}}}},"get":{"summary":"Listar documentos KYC","tags":["Pagamentos - Varejo Pay"],"description":"Retorna documentos KYC do tenant ordenados por data de envio.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/rekta-pay/documentos/{id}":{"delete":{"summary":"Remover documento KYC","tags":["Pagamentos - Varejo Pay"],"description":"Remove documento do Storage e banco. Documentos aprovados não podem ser removidos.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/rekta-pay/documentos/{id}/url":{"get":{"summary":"Gerar URL de visualização de documento KYC","tags":["Pagamentos - Varejo Pay"],"description":"Gera signed URL (5 min) para visualizar documento privado do bucket kyc-docs.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"expires_in":{"type":"number"}}}}}}}}},"/rekta-pay/kyc-status":{"get":{"summary":"Consultar status KYC","tags":["Pagamentos - Varejo Pay"],"description":"Status enxuto do KYC com cache (30s). Se cache velho, refaz GET no Pagar.me e atualiza.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"status_reason":{"type":"string","nullable":true},"updated_at":{"type":"string","nullable":true},"recipient_id":{"type":"string","nullable":true},"fonte":{"type":"string"}}}}}}}}},"/rekta-pay/pix-out":{"post":{"summary":"Saque instantâneo via Pix","tags":["Pagamentos - Varejo Pay"],"description":"Transferência instantânea via chave Pix. Exige 2FA, valida saldo real. Máximo R$ 50.000.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["amount_centavos","pix_key","confirmacao_2fa"],"properties":{"amount_centavos":{"type":"number"},"pix_key":{"type":"object","properties":{"type":{"type":"string","enum":["cpf","cnpj","email","phone","random"]},"value":{"type":"string"}}},"confirmacao_2fa":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/rekta-pay/audit-log":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/2fa/iniciar":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/2fa/verificar":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/socios":{"get":{"responses":{"200":{"description":"Default Response"}}},"post":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/socios/{id}":{"delete":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/socios/importar-qsa":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/admin/metrics":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/rekta-pay/admin/tenants":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/grades-padrao":{"get":{"summary":"Listar grades padrão","tags":["Catálogo - Grades"],"description":"Retorna grades de opções padrão (globais da plataforma + customizadas do tenant). Filtrável por vertical.","parameters":[{"schema":{"type":"string"},"in":"query","name":"vertical","required":false,"description":"Filtrar por vertical (ex: varejo, pet, saude)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar grade customizada","tags":["Catálogo - Grades"],"description":"Cria uma grade de opções customizada do tenant (ex: tamanhos específicos, cores da marca).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["vertical","nome_opcao","valores"],"properties":{"vertical":{"type":"string","description":"Vertical (ex: varejo, pet)"},"nome_opcao":{"type":"string","description":"Nome da opção (ex: Tamanho, Cor)"},"valores":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1},"hex":{"type":"string"},"imagem_url":{"type":"string"}},"additionalProperties":false}]},"description":"Valores possíveis (ex: [P, M, G] ou [{ nome: \"Linho Cinza\", imagem_url }])"},"posicao":{"type":"integer","default":0,"description":"Ordem de exibição"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/grades-padrao/{id}":{"put":{"summary":"Editar grade customizada","tags":["Catálogo - Grades"],"description":"Troca o nome e os valores de uma grade do tenant, inclusive as fotos das amostras.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome_opcao":{"type":"string","minLength":1},"valores":{"type":"array","items":{"anyOf":[{"type":"string"},{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1},"hex":{"type":"string"},"imagem_url":{"type":"string"}},"additionalProperties":false}]},"description":"Valores possíveis (ex: [P, M, G] ou [{ nome: \"Linho Cinza\", imagem_url }])"},"posicao":{"type":"integer"}},"minProperties":1,"additionalProperties":false}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir grade customizada","tags":["Catálogo - Grades"],"description":"Apaga uma grade do tenant. Produtos que já usam os valores continuam com eles.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Grade excluída"}}}},"/locais-estoque":{"get":{"summary":"Listar locais de estoque ativos","tags":["Logística - Locais de Estoque"],"description":"Retorna os locais que servem estoque (centros de distribuição) ativos do tenant, ordenados por principal (desc) e nome (asc). Use incluir_sem_estoque=true para trazer também pontos de retirada puros.","parameters":[{"schema":{"type":"boolean","default":false},"in":"query","name":"incluir_sem_estoque","required":false,"description":"Inclui locais com serve_estoque=false (ex.: exibir saldo legado lançado antes de o flag ser desligado)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"logradouro":{"type":["null","string"]},"principal":{"type":"boolean"},"ativo":{"type":"boolean"},"serve_estoque":{"type":"boolean"}}}}}}}}},"post":{"summary":"Criar local de estoque","tags":["Logística - Locais de Estoque"],"description":"Cria um novo centro de distribuição (tenant_location com serve_estoque=true). Campo \"endereco\" é mapeado para \"logradouro\" por compatibilidade.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","description":"Nome do centro de distribuição"},"endereco":{"type":"string","description":"Endereço (compat - mapeado para logradouro)"},"principal":{"type":"boolean","default":false,"description":"Se é o CD principal do tenant"},"cep":{"type":["string","null"],"description":"CEP de origem — usado no cálculo de frete"},"serve_despacho":{"type":"boolean","description":"Se o local pode ser origem de envio"},"serve_retirada":{"type":"boolean","description":"Se o local aceita retirada pelo cliente"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/locais-estoque/{id}":{"patch":{"summary":"Atualizar local de estoque","tags":["Logística - Locais de Estoque"],"description":"Atualiza campos permitidos de um centro de distribuição: nome, endereco (logradouro), principal e ativo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"endereco":{"type":"string","description":"Compat - mapeado para logradouro"},"principal":{"type":"boolean"},"ativo":{"type":"boolean"},"cep":{"type":["string","null"],"description":"CEP de origem — usado no cálculo de frete"},"serve_despacho":{"type":"boolean"},"serve_retirada":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizado com sucesso"}}},"delete":{"summary":"Desativar local de estoque","tags":["Logística - Locais de Estoque"],"description":"Soft delete - marca o centro de distribuição como ativo=false. Não remove registros de estoque_por_local vinculados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Desativado com sucesso"}}}},"/estoque-por-local":{"get":{"summary":"Consultar estoque por local","tags":["Logística - Locais de Estoque"],"description":"Retorna estoque discriminado por centro de distribuição. Se produto_id informado, filtra por produto; caso contrário, retorna todos os registros de estoque do tenant.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false,"description":"Filtrar por produto específico"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"local_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer"},"reservado":{"type":"integer"},"saldo_erp":{"type":["null","integer"],"description":"Em mãos no ERP (só leitura)"},"reservado_erp":{"type":["null","integer"],"description":"Reservado no ERP (só leitura)"},"minimo_alerta":{"type":["null","integer"]},"updated_at":{"type":"string","format":"date-time"},"local":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"principal":{"type":"boolean"}},"description":"Presente apenas quando filtrado por produto_id"}}}}}}}}},"post":{"summary":"Ajustar estoque de um produto num local","tags":["Logística - Locais de Estoque"],"description":"Ajuste manual de estoque. Recebe a quantidade ABSOLUTA contada pelo operador, calcula o delta contra o saldo atual e aplica via a RPC movimentar_estoque (origem \"manual\"), que grava o ledger de movimentações com autoria e motivo. Se o delta for zero, responde 204 sem gerar movimentação. Envie `saldo_esperado` (o saldo que a tela mostrava) para que o ajuste seja recusado com 409 `saldo_mudou` caso alguém tenha mexido no estoque enquanto a contagem estava aberta (D-9).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","local_id"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"local_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer","default":0,"minimum":0,"maximum":1000000,"description":"Quantidade total contada (absoluta), não o delta"},"minimo_alerta":{"type":["integer","null"],"description":"Quantidade mínima para alerta de reposição (não é saldo — gravado direto)"},"saldo_esperado":{"type":["integer","null"],"minimum":0,"maximum":1000000,"description":"OPCIONAL (D-9). O saldo que a tela leu antes da contagem. Se não bater com o saldo atual no momento do ajuste, nada é gravado e a resposta é 409 `saldo_mudou` com o saldo real, para o operador reapresentar a diferença. Omitido, o comportamento é o de sempre."},"motivo":{"type":"string","description":"Motivo do ajuste: contagem (inventário), avaria, perda (furto/extravio) ou correcao."},"observacao":{"type":["string","null"],"description":"Observação livre registrada no ledger"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Ajuste aplicado numa entrada já existente","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ajuste aplicado numa entrada já existente","properties":{"id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"local_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer"},"reservado":{"type":"integer"},"saldo_erp":{"type":["null","integer"],"description":"Em mãos no ERP (só leitura)"},"reservado_erp":{"type":["null","integer"],"description":"Reservado no ERP (só leitura)"},"minimo_alerta":{"type":["null","integer"]},"movimentacao_id":{"type":["null","string"]},"saldo_anterior":{"type":"integer"},"delta_aplicado":{"type":"integer"}}}}}},"201":{"description":"Entrada criada pelo ajuste","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Entrada criada pelo ajuste","properties":{"id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"local_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer"},"reservado":{"type":"integer"},"saldo_erp":{"type":["null","integer"],"description":"Em mãos no ERP (só leitura)"},"reservado_erp":{"type":["null","integer"],"description":"Reservado no ERP (só leitura)"},"minimo_alerta":{"type":["null","integer"]},"movimentacao_id":{"type":["null","string"]},"saldo_anterior":{"type":"integer"},"delta_aplicado":{"type":"integer"}}}}}},"204":{"description":"Sem alteração de saldo — nenhuma movimentação registrada"},"409":{"description":"O saldo mudou entre a leitura da tela e o ajuste — nada foi gravado (D-9)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"O saldo mudou entre a leitura da tela e o ajuste — nada foi gravado (D-9)","properties":{"error":{"type":"string","enum":["saldo_mudou"]},"message":{"type":"string"},"saldo_esperado":{"type":"integer"},"saldo_atual":{"type":"integer"},"quantidade_informada":{"type":"integer"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/estoque/skus":{"get":{"summary":"Grade de SKUs para a tela de Estoque","tags":["Logística - Locais de Estoque"],"description":"Todos os produtos do tenant com saldo, miniatura e variações, só com os campos da tela de Estoque. Sem paginação: a tela trabalha sobre o catálogo inteiro.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"sku":{"type":["null","string"]},"estoque":{"type":["null","integer"]},"thumb":{"type":["null","string"]},"variacoes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":["null","string"]},"sku":{"type":["null","string"]},"estoque":{"type":["null","integer"]},"ativo":{"type":["null","boolean"]}}}}}}}}}}}}}}},"/estoque-por-local/{id}":{"patch":{"summary":"Ajustar entrada de estoque por local","tags":["Logística - Locais de Estoque"],"description":"Ajusta uma entrada de estoque existente. \"quantidade\" é a contagem ABSOLUTA e passa pela RPC movimentar_estoque (exige motivo, gera ledger). \"minimo_alerta\" não é saldo e é gravado direto. O campo \"reservado\" NÃO é editável: reserva é escrita apenas pelo fluxo de pedidos — mexer nela à mão corrompe pedidos em aberto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"quantidade":{"type":"integer","minimum":0,"maximum":1000000,"description":"Quantidade total contada (absoluta), não o delta"},"minimo_alerta":{"type":["integer","null"]},"motivo":{"type":"string","description":"Motivo do ajuste: contagem (inventário), avaria, perda (furto/extravio) ou correcao. Obrigatório quando \"quantidade\" é informada."},"observacao":{"type":["string","null"],"description":"Observação livre registrada no ledger"},"saldo_esperado":{"type":["integer","null"],"minimum":0,"maximum":1000000,"description":"OPCIONAL (D-9), igual ao do POST: o saldo que a tela leu. Não batendo, 409 `saldo_mudou` e nada é gravado."}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Atualizado com sucesso"},"409":{"description":"O saldo mudou entre a leitura da tela e o ajuste — nada foi gravado (D-9)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"O saldo mudou entre a leitura da tela e o ajuste — nada foi gravado (D-9)","properties":{"error":{"type":"string","enum":["saldo_mudou"]},"message":{"type":"string"},"saldo_esperado":{"type":"integer"},"saldo_atual":{"type":"integer"},"quantidade_informada":{"type":"integer"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/estoque-importar":{"post":{"summary":"Importar estoque em massa via CSV","tags":["Logística - Locais de Estoque"],"description":"Bulk de estoque por SKU + nome do centro de distribuição. Resolve SKU→produto/variação e nome→local_id automaticamente. Cada linha é aplicada pela RPC movimentar_estoque (origem \"csv\"): a quantidade da planilha é a contagem ABSOLUTA e vira delta contra o saldo atual, gerando ledger com autoria e motivo. Processa em chunks; devolve relatório por linha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["linhas"],"properties":{"linhas":{"type":"array","items":{"type":"object","required":["sku","local_nome","quantidade"],"properties":{"sku":{"type":"string","description":"SKU do produto ou variação"},"local_nome":{"type":"string","description":"Nome do centro de distribuição (case-insensitive)"},"quantidade":{"type":"integer","minimum":0,"maximum":1000000,"description":"Quantidade total contada (absoluta), não o delta"}}}},"motivo":{"type":"string","default":"correcao","description":"Motivo do ajuste: contagem (inventário), avaria, perda (furto/extravio) ou correcao."},"observacao":{"type":["string","null"],"description":"Observação livre registrada no ledger de todas as linhas"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"importados":{"type":"integer","description":"Linhas que alteraram saldo"},"erros":{"type":"integer","description":"Linhas recusadas (SKU/CD não encontrado ou recusa da RPC)"},"total":{"type":"integer","description":"Total de linhas recebidas"},"updates":{"type":"integer","description":"Linhas que ajustaram uma entrada já existente"},"inserts":{"type":"integer","description":"Linhas que criaram uma entrada nova"},"sem_alteracao":{"type":"integer","description":"Linhas cujo saldo já era o informado"},"duplicadas":{"type":"integer","description":"Linhas repetidas de mesmo produto/variação/local: vale a última, os deltas não são somados"},"detalhes":{"type":"array","description":"Erros por linha (limitado às 50 primeiras ocorrências)","items":{"type":"object","additionalProperties":true,"properties":{"linha":{"type":"integer"},"sku":{"type":"string"},"local_nome":{"type":"string"},"erro":{"type":"string"},"message":{"type":"string"}}}}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/cupons/validar":{"post":{"summary":"Validar cupom (público)","tags":["Promoções - Cupons"],"description":"Valida e calcula desconto de um cupom. Suporta tipos: percentual, valor_fixo, frete_gratis, brinde, compre_ganhe, progressivo. Rate limit: 10/min por IP.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["codigo","account_id","subtotal_centavos"],"properties":{"codigo":{"type":"string"},"account_id":{"type":"string","format":"uuid"},"subtotal_centavos":{"type":"integer"},"qtd_itens":{"type":"integer"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"cliente_email":{"type":"string"},"cliente_cpf":{"type":"string"},"frete_centavos":{"type":"integer"}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/cupons":{"get":{"summary":"Listar cupons","tags":["Promoções - Cupons"],"description":"Listagem paginada de cupons com filtro por status ativo e tipo.","parameters":[{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativo","required":false},{"schema":{"type":"string","enum":["percentual","valor_fixo","frete_gratis","brinde","compre_ganhe","progressivo"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":100},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar cupom","tags":["Promoções - Cupons"],"description":"Cria cupom com código normalizado (UPPER). Suporta junction tables: produtos, categorias, brindes e faixas progressivas.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["codigo","tipo"],"properties":{"codigo":{"type":"string"},"tipo":{"type":"string","enum":["percentual","valor_fixo","frete_gratis","brinde","compre_ganhe","progressivo"]},"descricao":{"type":"string"},"ativo":{"type":"boolean","default":true},"valor":{"type":"number"},"valor_maximo":{"type":"number"},"valor_minimo":{"type":"number","default":0},"qtd_minima":{"type":"integer","default":0},"max_usos":{"type":["integer","null"]},"uso_por_cliente":{"type":"integer","default":1},"primeira_compra":{"type":"boolean","default":false},"escopo":{"type":"string","default":"pedido"},"validade_inicio":{"type":["string","null"]},"validade_fim":{"type":["string","null"]},"compre_qtd":{"type":"integer"},"ganhe_qtd":{"type":"integer"},"produtos":{"type":"array","items":{"type":"string","format":"uuid"}},"categorias":{"type":"array","items":{"type":"string","format":"uuid"}},"brindes":{"type":"array","items":{"type":"object","additionalProperties":true}},"faixas":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cupons/{id}":{"get":{"summary":"Detalhe do cupom","tags":["Promoções - Cupons"],"description":"Retorna cupom com junction tables: produtos, categorias, brindes e faixas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar cupom","tags":["Promoções - Cupons"],"description":"Atualiza campos e substitui junction tables (produtos, categorias, brindes, faixas) se fornecidas.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar cupom","tags":["Promoções - Cupons"],"description":"Soft delete (ativo = false).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/cupons/{id}/usos":{"get":{"summary":"Histórico de uso do cupom","tags":["Promoções - Cupons"],"description":"Lista usos do cupom com dados do pedido vinculado. Paginado.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estoque/verificar":{"post":{"summary":"Verificar disponibilidade de estoque","tags":["Logística - Estoque"],"description":"Verifica disponibilidade de estoque para uma lista de itens (produto + variação + quantidade). Rota interna service-to-service, autenticada via header X-Internal-Key.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["itens"],"properties":{"itens":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}},"required":["produto_id","quantidade"]}},"account_id":{"type":"string","format":"uuid","description":"Tenant do pedido (ativa guard multi-CD)"}}}}},"required":true},"security":[{"internalKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"disponivel":{"type":"boolean"},"indisponiveis":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/estoque/reservar":{"post":{"summary":"Reservar estoque para um pedido","tags":["Logística - Estoque"],"description":"Reserva estoque de todos os itens de um pedido (via pedido_id + account_id). Retorna 409 se estoque insuficiente. O corpo com `itens[]` foi descontinuado e responde 410. Rota interna service-to-service.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","description":"DESCONTINUADO — responde 410. Sem pedido não há dono da reserva. Use pedido_id + account_id.","items":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1},"local_id":{"type":"string","format":"uuid"}},"required":["produto_id","quantidade","local_id"]}},"pedido_id":{"type":"string","format":"uuid","description":"ID do pedido para resolver itens automaticamente"},"account_id":{"type":"string","format":"uuid","description":"Tenant do pedido (obrigatório se pedido_id informado)"}}}}}},"security":[{"internalKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["estoque_insuficiente"]},"mensagem":{"type":"string"}}}}}},"410":{"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/estoque/confirmar-envio":{"post":{"summary":"Confirmar envio e baixar estoque","tags":["Logística - Estoque"],"description":"Confirma o despacho e executa a baixa real no estoque (decrementa quantidade e encerra a reserva do pedido). Aceita SOMENTE `pedido_id` + `account_id`; o corpo com `itens[]` foi descontinuado e responde 410. Rota interna service-to-service.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1},"local_id":{"type":"string","format":"uuid"}},"required":["produto_id","quantidade","local_id"]}},"pedido_id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"}}}}}},"security":[{"internalKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"410":{"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/estoque/cancelar-reserva":{"post":{"summary":"Cancelar reserva de estoque","tags":["Logística - Estoque"],"description":"Libera a reserva de estoque de um pedido (via pedido_id + account_id). Usado no cancelamento. O corpo com `itens[]` foi descontinuado e responde 410. Rota interna service-to-service.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1},"local_id":{"type":"string","format":"uuid"}},"required":["produto_id","quantidade","local_id"]}},"pedido_id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"}}}}}},"security":[{"internalKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"410":{"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ramo `itens[]` descontinuado — envie `pedido_id` + `account_id`","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/transferencias":{"get":{"summary":"Listar transferências de estoque","tags":["Logística - Transferências"],"description":"Retorna todas as transferências do tenant com dados de origem, destino, criador e itens. Filtrável por status, origem e destino.","parameters":[{"schema":{"type":"string","enum":["pendente","em_transito","recebida","cancelada","todas"]},"in":"query","name":"status","required":false,"description":"Filtrar por status (ou \"todas\" para ignorar)"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"origem_id","required":false,"description":"Filtrar por local de origem"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"destino_id","required":false,"description":"Filtrar por local de destino"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"origem_id":{"type":"string","format":"uuid"},"destino_id":{"type":"string","format":"uuid"},"status":{"type":"string","enum":["pendente","em_transito","recebida","cancelada"]},"observacao":{"type":["null","string"]},"created_at":{"type":"string","format":"date-time"},"origem":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"destino":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"created_by_profile":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"transferencia_itens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":["null","string"]},"quantidade":{"type":"integer"},"quantidade_recebida":{"type":"integer"},"lote_codigo":{"type":["null","string"]}}}}}}}}}}}},"post":{"summary":"Criar transferência de estoque","tags":["Logística - Transferências"],"description":"Cria uma transferência com status \"pendente\" entre dois centros de distribuição. Valida disponibilidade na origem antes de criar. Origem e destino devem ser diferentes.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["origem_id","destino_id","itens"],"properties":{"origem_id":{"type":"string","format":"uuid","description":"ID do CD de origem"},"destino_id":{"type":"string","format":"uuid","description":"ID do CD de destino"},"observacao":{"type":"string"},"itens":{"type":"array","minItems":1,"items":{"type":"object","required":["produto_id","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1,"maximum":1000000},"lote_codigo":{"type":["string","null"],"maxLength":20,"description":"Lote específico a transferir (bipe do DM). NULL = FEFO na origem."}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/transferencias/{id}":{"get":{"summary":"Detalhe de transferência","tags":["Logística - Transferências"],"description":"Retorna dados completos de uma transferência com itens, origem, destino e criador.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/transferencias/{id}/enviar":{"patch":{"summary":"Enviar transferência","tags":["Logística - Transferências"],"description":"Muda status de \"pendente\" para \"em_transito\" e reserva estoque na origem. Valida disponibilidade antes de reservar.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Enviada com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/transferencias/{id}/receber":{"patch":{"summary":"Receber transferência","tags":["Logística - Transferências"],"description":"Confirma recebimento de uma transferência \"em_transito\". Decrementa estoque na origem, incrementa no destino. Aceita recebimento parcial (quantidade_recebida por item); se não informado, recebe tudo.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Recebida com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/transferencias/{id}/cancelar":{"patch":{"summary":"Cancelar transferência","tags":["Logística - Transferências"],"description":"Cancela uma transferência pendente ou em trânsito. Se estava \"em_transito\", libera as reservas de estoque na origem. Transferências já recebidas ou canceladas não podem ser canceladas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Cancelada com sucesso"},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos":{"get":{"summary":"Listar recebimentos de mercadoria","tags":["Logística - Recebimentos"],"description":"Lista os recebimentos do tenant (mais recentes primeiro), com nome do local e totais agregados de itens e SKUs.","parameters":[{"schema":{"type":"string","enum":["em_andamento","confirmado","cancelado"]},"in":"query","name":"status","required":false,"description":"Filtrar por status"},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"recebimentos":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"local_id":{"type":"string","format":"uuid"},"local_nome":{"type":["null","string"]},"tipo":{"type":"string","enum":["compra","producao"]},"status":{"type":"string","enum":["em_andamento","confirmado","cancelado"]},"fornecedor":{"type":["null","string"]},"documento":{"type":["null","string"]},"observacao":{"type":["null","string"]},"created_by":{"type":["null","string"]},"confirmado_em":{"type":["null","string"]},"confirmado_por":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"total_itens":{"type":"integer"},"total_skus":{"type":"integer"}}}},"total":{"type":"integer"}}}}}}}},"post":{"summary":"Abrir recebimento de mercadoria","tags":["Logística - Recebimentos"],"description":"Abre um recebimento com status \"em_andamento\" num local que sirva estoque. Nada é movimentado até a confirmação.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["local_id"],"properties":{"local_id":{"type":"string","format":"uuid","description":"Local de estoque que vai receber"},"tipo":{"type":"string","enum":["compra","producao"],"default":"compra"},"fornecedor":{"type":["string","null"]},"documento":{"type":["string","null"],"description":"Nota fiscal / ordem de produção"},"observacao":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"recebimento":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"local_id":{"type":"string","format":"uuid"},"local_nome":{"type":["null","string"]},"tipo":{"type":"string","enum":["compra","producao"]},"status":{"type":"string","enum":["em_andamento","confirmado","cancelado"]},"fornecedor":{"type":["null","string"]},"documento":{"type":["null","string"]},"observacao":{"type":["null","string"]},"created_by":{"type":["null","string"]},"confirmado_em":{"type":["null","string"]},"confirmado_por":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"total_itens":{"type":"integer"},"total_skus":{"type":"integer"}}}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos/{id}":{"get":{"summary":"Detalhe do recebimento","tags":["Logística - Recebimentos"],"description":"Retorna o recebimento e seus itens, já enriquecidos com nome/SKU do produto, nome da variação e se o produto é controlado por lote.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"recebimento":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"local_id":{"type":"string","format":"uuid"},"local_nome":{"type":["null","string"]},"tipo":{"type":"string","enum":["compra","producao"]},"status":{"type":"string","enum":["em_andamento","confirmado","cancelado"]},"fornecedor":{"type":["null","string"]},"documento":{"type":["null","string"]},"observacao":{"type":["null","string"]},"created_by":{"type":["null","string"]},"confirmado_em":{"type":["null","string"]},"confirmado_por":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"total_itens":{"type":"integer"},"total_skus":{"type":"integer"}}},"itens":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"recebimento_id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"produto_nome":{"type":"string"},"produto_sku":{"type":["null","string"]},"variacao_nome":{"type":["null","string"]},"controlado_por_lote":{"type":"boolean"},"quantidade":{"type":"integer"},"lote_codigo":{"type":["null","string"]},"data_validade":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos/{id}/itens":{"post":{"summary":"Bipar item no recebimento","tags":["Logística - Recebimentos"],"description":"Adiciona quantidade ao recebimento. Se já existe linha com a mesma combinação (produto + variação + lote), SOMA a quantidade à existente — é isso que faz o bipe repetido acumular em vez de duplicar linha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1,"maximum":1000000,"default":1,"description":"Quanto somar (default 1 = um bipe)"},"lote_codigo":{"type":["string","null"]},"data_validade":{"type":["string","null"],"format":"date","description":"YYYY-MM-DD"},"scan_id":{"type":["string","null"],"format":"uuid","description":"Identificador da leitura (dedup de rebipe após falha de rede)"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"item":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"recebimento_id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"produto_nome":{"type":"string"},"produto_sku":{"type":["null","string"]},"variacao_nome":{"type":["null","string"]},"controlado_por_lote":{"type":"boolean"},"quantidade":{"type":"integer"},"lote_codigo":{"type":["null","string"]},"data_validade":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos/{id}/itens/{itemId}":{"patch":{"summary":"Corrigir item do recebimento","tags":["Logística - Recebimentos"],"description":"Define a quantidade ABSOLUTA do item (diferente do POST, que soma) e permite corrigir lote e validade da linha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"quantidade":{"type":"integer","minimum":0,"maximum":1000000,"description":"Quantidade final do item"},"lote_codigo":{"type":["string","null"],"maxLength":20},"data_validade":{"type":["string","null"],"format":"date"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"item":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"recebimento_id":{"type":"string","format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["null","string"]},"produto_nome":{"type":"string"},"produto_sku":{"type":["null","string"]},"variacao_nome":{"type":["null","string"]},"controlado_por_lote":{"type":"boolean"},"quantidade":{"type":"integer"},"lote_codigo":{"type":["null","string"]},"data_validade":{"type":["null","string"]},"created_at":{"type":"string"},"updated_at":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Remover item do recebimento","tags":["Logística - Recebimentos"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos/{id}/confirmar":{"post":{"summary":"Confirmar recebimento (dá entrada no estoque)","tags":["Logística - Recebimentos"],"description":"Aplica a entrada de estoque de todos os itens via RPC movimentar_estoque / movimentar_estoque_lote, gerando ledger em movimentacoes_estoque. All-or-nothing: se qualquer item for recusado, os já aplicados são revertidos e nada fica pela metade.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"movimentacoes":{"type":"integer"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/recebimentos/{id}/cancelar":{"post":{"summary":"Cancelar recebimento","tags":["Logística - Recebimentos"],"description":"Cancela um recebimento em andamento. Recebimentos já confirmados não podem ser cancelados — o estoque já entrou.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/movimentacoes-estoque":{"get":{"summary":"Extrato de estoque (movimentações de saldo e eventos de reserva)","tags":["Logística - Recebimentos"],"description":"Mescla duas fontes, mais recentes primeiro: o ledger append-only de SALDO FÍSICO (`movimentacoes_estoque`, itens com `tipo: \"saldo\"`) e os eventos de COMPROMISSO (`estoque_reservas`, itens com `tipo: \"reserva\"`, um na criação e outro no encerramento). Item de reserva não tem `delta`/`saldo_*` porque reserva não muda saldo. Filtrável por produto, variação e local; com `documento_id` o extrato é só o ledger, porque reserva não pertence a documento de entrada.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"variacao_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"local_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"documento_id","required":false},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"boolean","default":false},"in":"query","name":"incluir_reservas","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"movimentacoes":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"produto_id":{"type":["null","string"]},"variacao_id":{"type":["null","string"]},"local_id":{"type":["null","string"]},"produto_nome":{"type":"string"},"produto_sku":{"type":["null","string"]},"local_nome":{"type":["null","string"]},"codigo_lote":{"type":["null","string"]},"delta":{"type":"integer"},"saldo_anterior":{"type":"integer"},"saldo_posterior":{"type":"integer"},"motivo":{"type":"string"},"origem":{"type":"string"},"usuario_id":{"type":["null","string"]},"documento_tipo":{"type":["null","string"]},"documento_id":{"type":["null","string"]},"observacao":{"type":["null","string"]},"created_at":{"type":"string"},"tipo":{"type":"string","enum":["saldo","reserva"]},"pedido_numero":{"type":["null","string"]},"marketplace_provider":{"type":["null","string"]},"reserva_id":{"type":"string","format":"uuid"},"evento":{"type":"string","enum":["criada","encerrada"]},"quantidade":{"type":"integer"},"dono_tipo":{"type":"string"},"dono_id":{"type":["null","string"]},"reserva_status":{"type":"string"},"motivo_encerramento":{"type":["null","string"]}}}},"total":{"type":"integer"}}}}}}}}},"/setup-status":{"get":{"summary":"Status do setup guide","tags":["Setup"],"description":"Retorna steps de configuração por vertical do tenant com status de conclusão, progresso e dismissed flag.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/setup-status/primeiros-passos":{"get":{"summary":"Sinais do guia Primeiros passos","tags":["Setup"],"description":"Diz quais passos de colocar a loja no ar já foram feitos (produto, personalização, frete, pagamento, domínio, pedido) e se o usuário ocultou o guia. Cada sinal é uma leitura de existência, sem contagem.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/setup-status/dismiss":{"patch":{"summary":"Dispensar setup guide","tags":["Setup"],"description":"Marca o setup guide como dispensado para o usuário atual.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/events":{"post":{"summary":"Coletar eventos do pixel","tags":["Marketing - Tracking Pixel"],"description":"Endpoint público de coleta do pixel _rkt. Rate limit 100/min. Persiste eventos, encaminha para Meta CAPI e GA4 com portão LGPD.","responses":{"200":{"description":"Default Response"}}}},"/tracking/heartbeat":{"post":{"summary":"Heartbeat de presença","tags":["Marketing - Tracking Pixel"],"description":"Ping público do pixel (_rkt) para manter a sessão viva no contador AO VIVO. Sem JWT. Body: { tid, sid }.","responses":{"200":{"description":"Default Response"}}}},"/tracking/pulse":{"get":{"summary":"PulseBar em tempo real","tags":["Marketing - Tracking Pixel"],"description":"Métricas em tempo real: sessões ativas, visitantes hoje, receita hoje, conversão 7d com variações.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/funil-perdas":{"get":{"summary":"Perdas do checkout e funil por dispositivo","tags":["Marketing - Tracking Pixel"],"description":"Motivos de abandono no checkout (frete sem cobertura, erro de campo, desistência por etapa) e o funil por dispositivo.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/insights":{"get":{"summary":"Insights do Analytics","tags":["Marketing - Tracking Pixel"],"description":"Buscas sem resultado, mapa de visitas e vendas por dia e hora, e vendas por estado.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/timeline":{"get":{"summary":"Timeline receita/visitantes","tags":["Marketing - Tracking Pixel"],"description":"Receita e visitantes únicos por dia no período selecionado.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/produtos":{"get":{"summary":"Performance por produto","tags":["Marketing - Tracking Pixel"],"description":"Views, add to cart, purchases e receita por produto no período.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/funil":{"get":{"summary":"Funil de conversão","tags":["Marketing - Tracking Pixel"],"description":"Funil monetizado com visitantes distintos por etapa, taxa de avanço e drop-off.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/resumo":{"get":{"summary":"Resumo de métricas","tags":["Marketing - Tracking Pixel"],"description":"Métricas consolidadas: visitantes, sessões, receita, conversão, ticket médio, abandono, tempo de sessão com variações período-a-período.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/attribution":{"get":{"summary":"Atribuição por canal","tags":["Marketing - Tracking Pixel"],"description":"Canais de aquisição com receita atribuída. Suporta first-touch ou last-touch. Inclui métodos de pagamento.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false},{"schema":{"type":"string","enum":["first","last"],"default":"first"},"in":"query","name":"touch","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/hourly":{"get":{"summary":"Pedidos por hora","tags":["Marketing - Tracking Pixel"],"description":"Distribuição de pedidos por hora do dia com pico identificado.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/devices":{"get":{"summary":"Dispositivos e browsers","tags":["Marketing - Tracking Pixel"],"description":"Breakdown de sessões por tipo de dispositivo e navegador.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/searches":{"get":{"summary":"Top buscas internas","tags":["Marketing - Tracking Pixel"],"description":"Top 10 termos mais buscados na loja no período.","parameters":[{"schema":{"type":"string","default":"30d"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/geo":{"get":{"summary":"Segmentação geográfica","tags":["Marketing - Tracking Pixel"],"description":"Visitantes por cidade e estado com percentuais. Top 50 cidades.","parameters":[{"schema":{"type":"string","default":"30"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tracking/web-vitals":{"get":{"summary":"Core Web Vitals","tags":["Marketing - Tracking Pixel"],"description":"LCP, INP e CLS P75 com avaliação (bom/médio/ruim), variação e sparkline diária.","parameters":[{"schema":{"type":"string","default":"7"},"in":"query","name":"periodo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/clientes":{"get":{"summary":"Listar clientes","tags":["Clientes"],"description":"Retorna clientes do tenant com paginação, busca textual (nome, email, telefone, CPF) e filtros por lifecycle_stage e canal de origem. Enriquece com totais de pedidos via RPC.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false,"description":"Página"},{"schema":{"type":"integer","default":20},"in":"query","name":"page_size","required":false,"description":"Itens por página (handler limita a 50)"},{"schema":{"type":"string"},"in":"query","name":"busca","required":false,"description":"Busca por nome, email, telefone ou CPF"},{"schema":{"type":"string"},"in":"query","name":"lifecycle","required":false,"description":"Filtro por lifecycle_stage (CSV: lead,prospect,customer)"},{"schema":{"type":"string"},"in":"query","name":"origem","required":false,"description":"Filtro por canal de origem (whatsapp, crm, loja)"},{"schema":{"type":"string","enum":["recentes","nome","gasto","pedidos","contato"]},"in":"query","name":"ordem","required":false,"description":"Ordem: recentes (padrão), nome, gasto, pedidos ou contato. Sempre com o id como desempate."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}}},"/clientes/contagens":{"get":{"summary":"Contagem de clientes por estágio","tags":["Clientes"],"description":"Total de clientes do tenant e por lifecycle_stage (sem estágio conta como lead), para as abas da lista do painel.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"todos":{"type":"integer"},"lead":{"type":"integer"},"prospect":{"type":"integer"},"customer":{"type":"integer"},"repeat":{"type":"integer"},"vip":{"type":"integer"},"lapsed":{"type":"integer"}}}}}}}}},"/clientes/{id}":{"get":{"summary":"Detalhe do cliente","tags":["Clientes"],"description":"Retorna dados completos do cliente com endereços, últimos 20 pedidos, leads vinculados, conversas e lifetime value calculado.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar cliente","tags":["Clientes"],"description":"Atualiza dados de um cliente do tenant. Suporta PF/PJ com validação de CNPJ e razão social. Sincroniza com índice de busca.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"email":{"type":"string","format":"email"},"telefone":{"type":"string"},"cpf":{"type":"string"},"notas":{"type":"string"},"tipo_pessoa":{"type":"string","enum":["pf","pj"]},"cnpj":{"type":"string","description":"14 dígitos (obrigatório se PJ)"},"razao_social":{"type":"string","description":"Obrigatório se PJ"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/clientes/{id}/enderecos":{"get":{"summary":"Listar endereços do cliente (admin)","tags":["Clientes"],"description":"Retorna endereços do cliente ordenados por padrão. Usado pelo PDV, checkout admin, draft order e edit order.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"enderecos":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/clientes/{id}/timeline":{"get":{"summary":"Timeline do cliente (Klaviyo-style)","tags":["Clientes"],"description":"Retorna eventos cronológicos unificados: evento_negocio, pedidos, mensagens e tracking_eventos. Suporta cursor pagination e filtro por categoria.","parameters":[{"schema":{"type":"integer","default":50,"maximum":100},"in":"query","name":"limit","required":false,"description":"Máx. itens (até 100)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"before","required":false,"description":"Cursor ISO para paginação"},{"schema":{"type":"string","enum":["compra","carrinho","mensagem","navegacao"]},"in":"query","name":"filter","required":false,"description":"Filtro por categoria"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"timeline":{"type":"array","items":{"type":"object","additionalProperties":true}},"tem_mais":{"type":"boolean"},"proximo_cursor":{"type":["null","string"]}}}}}}}}},"/clientes/resolver":{"post":{"summary":"Resolver ou criar cliente","tags":["Clientes"],"description":"Busca cliente existente por email/telefone ou cria um novo. Usado pelo PDV, checkout admin e CRM para deduplicação canônica.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"email":{"type":"string","format":"email"},"telefone":{"type":"string"},"cpf":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/clientes/public/resolver-auth":{"post":{"summary":"Vincular auth_user_id ao cliente (pós-login OTP)","tags":["Clientes"],"description":"Chamado após login OTP: vincula auth_user_id ao registro de cliente existente por email/telefone, ou cria um novo cliente se não houver correspondência. O match usa apenas o email/telefone verificados do auth.users; email e telefone do body são ignorados (o nome do body vale só na criação).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"email":{"type":"string","format":"email"},"telefone":{"type":"string"}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/clientes/public/me":{"get":{"summary":"Dados do cliente logado","tags":["Clientes"],"description":"Retorna dados do cliente autenticado via OTP, incluindo endereços. Sem usuário ou sem cliente vinculado, retorna 200 com null. Inclui fallback de vinculação automática por email/telefone.","responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Editar dados do próprio cliente","tags":["Clientes"],"description":"Cliente final autenticado edita seus próprios dados (nome, telefone, CPF). Email não é editável por segurança.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"telefone":{"type":["string","null"]},"cpf":{"type":["string","null"]}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/clientes/public/pedidos":{"get":{"summary":"Pedidos do cliente logado","tags":["Clientes"],"description":"Lista pedidos do cliente autenticado com itens, log de status e paginação. Usado pela área Minha Conta.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":10,"maximum":50},"in":"query","name":"page_size","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}}},"/clientes/public/enderecos":{"get":{"summary":"Listar endereços do cliente logado","tags":["Clientes"],"description":"Retorna endereços do cliente autenticado, ordenados por padrão.","responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Adicionar endereço (máx. 5)","tags":["Clientes"],"description":"Cliente final adiciona um novo endereço. Limite de 5 endereços por cliente. Se marcado como padrão, desmarca os anteriores.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cep","logradouro","numero","bairro","cidade","uf"],"properties":{"apelido":{"type":["string","null"]},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":["string","null"]},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string","maxLength":2},"padrao":{"type":"boolean","default":false}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/clientes/public/enderecos/{id}":{"patch":{"summary":"Editar endereço do cliente","tags":["Clientes"],"description":"Cliente final edita um endereço existente. Se marcado como padrão, desmarca os demais.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"apelido":{"type":["string","null"]},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":["string","null"]},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string","maxLength":2},"padrao":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover endereço do cliente","tags":["Clientes"],"description":"Cliente final remove um endereço existente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/clientes/public/auto-login":{"post":{"summary":"Gerar magic link para auto-login (1-click)","tags":["Clientes"],"description":"Rota pública sem auth Supabase. Valida token proprietário, gera magic link real Supabase e retorna redirect_url para auto-signIn. Vincula auth_user_id ao cliente se necessário.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string","description":"Token proprietário de magic link"},"redirect":{"type":"string","description":"Caminho interno pós-login (URL externa cai em /minha-conta)"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirect_url":{"type":"string"},"cliente_nome":{"type":"string"}}}}}}}}},"/gateway-pagamento/config":{"get":{"summary":"Consultar configuração do gateway de pagamento","tags":["Pagamentos - Gateway"],"description":"Retorna a configuração do gateway do tenant (NUNCA retorna secret keys). Filtro opcional por provider.","parameters":[{"schema":{"type":"string"},"in":"query","name":"provider","required":false,"description":"Provider específico (pagarme, asaas, cielo, rede, dom_pagamentos, nupay)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"account_id":{"type":"string"},"provider":{"type":"string"},"ativo":{"type":"boolean"},"public_key":{"type":"string","nullable":true},"taxas":{"type":"object","additionalProperties":true},"config":{"type":"object","additionalProperties":true},"nome_exibicao":{"type":"string","nullable":true},"testado_em":{"type":"string","nullable":true},"webhook_url":{"type":"string","nullable":true}}}}}}}},"post":{"summary":"Criar ou atualizar configuração do gateway","tags":["Pagamentos - Gateway"],"description":"Upsert das credenciais do gateway de pagamento. Encripta secret_key e webhook_secret. Auto-define como primário se for o primeiro.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["secret_key"],"properties":{"provider":{"type":"string","enum":["pagarme","asaas","cielo","rede","dom_pagamentos","mercadopago","nupay"]},"secret_key":{"type":"string","description":"Chave secreta do provider (encriptada antes de salvar)"},"public_key":{"type":"string"},"webhook_secret":{"type":"string"},"taxas":{"type":"object","additionalProperties":true},"nome_exibicao":{"type":"string"},"config":{"type":"object","description":"Config adicional (merchant_id, pv, sandbox, etc.)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"provider":{"type":"string"},"ativo":{"type":"boolean"},"webhook_url":{"type":"string","nullable":true}}}}}},"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string"},"provider":{"type":"string"},"ativo":{"type":"boolean"},"webhook_url":{"type":"string","nullable":true}}}}}}}},"delete":{"summary":"Remover configuração do gateway","tags":["Pagamentos - Gateway"],"description":"Desconecta o gateway removendo a configuração. Aceita provider opcional para não apagar outros providers.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/primario":{"patch":{"summary":"Definir provider primário","tags":["Pagamentos - Gateway"],"description":"Define qual provider é o gateway primário quando o tenant tem múltiplos third-party ativos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","nullable":true,"description":"Provider a definir como primário (null para remover)"},"tipo":{"type":"string","nullable":true,"enum":["rekta_pay","third_party","none",null],"description":"Eixo macro do gateway primário. Quando informado, gravado junto com o provider."}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"gateway_primario":{"type":"string","nullable":true},"gateway_primario_provider":{"type":"string","nullable":true}}}}}}}}},"/gateway-pagamento/testar":{"post":{"summary":"Testar conexão com o gateway","tags":["Pagamentos - Gateway"],"description":"Testa as credenciais salvas contra a API do provider. Dispatch por provider via health-check unificado.","parameters":[{"schema":{"type":"string"},"in":"query","name":"provider","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"message":{"type":"string"},"status":{"type":"string"},"checked_at":{"type":"string","nullable":true}}}}}}}}},"/gateway-pagamento/ativar":{"patch":{"summary":"Ativar ou desativar o gateway","tags":["Pagamentos - Gateway"],"description":"Alterna o estado ativo do gateway. Exige teste de conexão bem-sucedido antes de ativar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ativo"],"properties":{"ativo":{"type":"boolean"},"provider":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ativo":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/sandbox":{"patch":{"summary":"Alternar modo sandbox","tags":["Pagamentos - Gateway"],"description":"Alterna a flag sandbox sem reenviar credenciais. Reseta testado_em e ativo (ambientes usam URLs e contas distintas).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["sandbox","provider"],"properties":{"sandbox":{"type":"boolean"},"provider":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"sandbox":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/taxas":{"put":{"summary":"Atualizar taxas do gateway","tags":["Pagamentos - Gateway"],"description":"Atualiza apenas as taxas personalizadas do gateway. Aceita provider opcional.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["taxas"],"properties":{"taxas":{"type":"object","description":"Mapa de taxas por método (ex: { pix: 0.99, credito_1x: 4.99 })"},"provider":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/webhook-url":{"get":{"summary":"Obter URL de webhook canônica","tags":["Pagamentos - Gateway"],"description":"Retorna a URL de webhook canônica pelo provider, com instruções de configuração no painel do provedor.","parameters":[{"schema":{"type":"string"},"in":"query","name":"provider","required":false,"description":"Provider (default: pagarme)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"instrucoes":{"type":"string"}}}}}}}}},"/gateway-pagamento/{id}/health-check":{"post":{"summary":"Health check de um gateway específico","tags":["Pagamentos - Gateway"],"description":"Health check sob demanda para um gateway por ID. Valida que pertence ao tenant do usuário.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"error":{"type":"string","nullable":true},"checked_at":{"type":"string"}}}}}}}}},"/internal/gateway-health-check-all":{"post":{"summary":"Health check de todos os gateways ativos (interno)","tags":["Pagamentos - Gateway"],"description":"Cron interno - verifica saúde de todos os gateways ativos. Protegido por header x-internal-secret.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/gateway-pagamento/taxas-plataforma":{"get":{"summary":"Consultar taxas de plataforma por mês","tags":["Pagamentos - Gateway"],"description":"Resumo das taxas de plataforma (1%) agrupadas por mês de referência.","parameters":[{"schema":{"type":"string"},"in":"query","name":"limit","required":false,"description":"Máximo de meses (default 12, max 24)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"mes_referencia":{"type":"string"},"total_centavos":{"type":"number"},"qtd_pedidos":{"type":"number"},"status":{"type":"string"}}}}}}}}}}}},"/gateway-pagamento/asaas/config":{"get":{"summary":"Consultar configuração Asaas enriquecida","tags":["Pagamentos - Asaas"],"description":"Retorna config enriquecida com flag sandbox, status derivado de testado_em, e webhook_url servida pelo backend.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"provider":{"type":"string"},"sandbox":{"type":"boolean"},"testado_em":{"type":"string","nullable":true},"status":{"type":"string","enum":["ok","invalid_credentials","pending"]},"webhook_secret_configurado":{"type":"boolean"},"webhook_url":{"type":"string"}}}}}}}}},"/gateway-pagamento/asaas/webhook-secret":{"patch":{"summary":"Cadastrar webhook secret do Asaas","tags":["Pagamentos - Asaas"],"description":"Cadastra o Authentication Token do webhook Asaas (shared secret). Mínimo 8 caracteres.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["webhook_secret"],"properties":{"webhook_secret":{"type":"string","minLength":8}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/webhook/asaas/{accountId}":{"post":{"summary":"Receber webhook do Asaas","tags":["Webhooks - Asaas"],"description":"Rota pública. Validação via shared secret (asaas-access-token). Idempotência via gateway_webhook_events. Atualiza status do pedido conforme mapa Asaas → Varejo Hub.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"payment":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"externalReference":{"type":"string","nullable":true},"value":{"type":"number"}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/nupay/{accountId}/payments":{"post":{"summary":"Receber webhook de pagamento NuPay","tags":["Webhooks - NuPay"],"description":"Rota pública. Valida HMAC (X-Spin-Signature) + anti-replay (X-Spin-Timestamp, janela 5min). Atualiza status do pedido.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pspReferenceId":{"type":"string"},"referenceId":{"type":"string","nullable":true},"status":{"type":"string"},"amount":{"type":"number"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/nupay/{accountId}/refunds":{"post":{"summary":"Receber webhook de estorno NuPay","tags":["Webhooks - NuPay"],"description":"Rota pública. Valida HMAC + timestamp. Quando refund REFUNDED, marca pedido como estornado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"refundId":{"type":"string"},"parentReferenceId":{"type":"string"},"pspReferenceId":{"type":"string"},"status":{"type":"string"},"amount":{"type":"number"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"status":{"type":"string"}}}}}}}}},"/webhook/nupay/{accountId}":{"post":{"summary":"Receber webhook NuPay (unificado)","tags":["Webhooks - NuPay"],"description":"Rota de compatibilidade que aceita pagamento ou estorno num único endpoint. Roteia por presença de refundId no body.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pspReferenceId":{"type":"string"},"refundId":{"type":"string","nullable":true},"status":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/mercado-pago/init":{"post":{"summary":"Iniciar fluxo OAuth2 com Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Retorna authorize_url para redirecionar o lojista ao Mercado Pago (OAuth2 Marketplace).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"}}}}}}}}},"/gateway-pagamento/mercado-pago/callback":{"post":{"summary":"Callback OAuth2 do Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Recebe code + state do redirect MP, troca por tokens via exchangeCodeForToken, e salva com upsert.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string","description":"Código de autorização retornado pelo MP"},"state":{"type":"string","description":"State HMAC com binding de tenant"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"message":{"type":"string"},"user_id":{"type":"number"}}}}}}}}},"/gateway-pagamento/mercado-pago/config":{"get":{"summary":"Consultar configuração do Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Retorna config visível (NUNCA tokens). Usada para renderizar tela de overview do MP.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"additionalProperties":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"provider":{"type":"string"},"user_id":{"type":"number","nullable":true},"public_key":{"type":"string","nullable":true},"live_mode":{"type":"boolean","nullable":true},"conectado_em":{"type":"string","nullable":true},"status":{"type":"string","enum":["ok","invalid_credentials","unreachable","pending","disabled"]},"webhook_secret_configurado":{"type":"boolean"},"webhook_url":{"type":"string"}}}}}}}},"delete":{"summary":"Desconectar Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Remove a integração OAuth2 do Mercado Pago, apagando tokens e configuração.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/mercado-pago/ativar":{"patch":{"summary":"Ativar ou desativar Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Exige health-check OK e webhook_secret configurado antes de ativar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ativo"],"properties":{"ativo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ativo":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/mercado-pago/webhook-secret":{"patch":{"summary":"Cadastrar chave de assinatura do webhook MP","tags":["Pagamentos - Mercado Pago"],"description":"Lojista cola a Chave de Assinatura copiada do painel MP. Obrigatória para ativar webhooks.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["webhook_secret"],"properties":{"webhook_secret":{"type":"string","minLength":8}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/gateway-pagamento/mercado-pago/health-check":{"post":{"summary":"Validar credenciais e disponibilidade do Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Consulta GET /users/me com o access_token atual (refresh se preciso). Atualiza status, last_health_check_at e last_health_error.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string","enum":["ok","invalid_credentials","unreachable","pending","disabled"]},"last_health_check_at":{"type":"string"},"last_health_error":{"type":"string","nullable":true},"user_id":{"type":"number","nullable":true},"capacidades":{"type":"object","properties":{"pix":{"type":"string","enum":["sim","nao","desconhecido"]},"cartao":{"type":"string","enum":["sim","nao","desconhecido"]},"boleto":{"type":"string","enum":["sim","nao","desconhecido"]},"fonte":{"type":"string","enum":["mercado_pago","cache","indisponivel"]},"verificado_em":{"type":"string","nullable":true},"erro":{"type":"string","nullable":true}}}}}}}}}}},"/gateway-pagamento/mercado-pago/capacidades":{"get":{"summary":"Capacidades reais da conta Mercado Pago do lojista","tags":["Pagamentos - Mercado Pago"],"description":"Consulta GET /v1/payment_methods com o token do tenant e devolve o que a CONTA aceita (pix/cartao/boleto). Cache de 10 min por tenant. Falha da MP devolve \"desconhecido\", nunca erro.","parameters":[{"schema":{"type":"boolean"},"in":"query","name":"forcar","required":false,"description":"Ignora o cache e consulta a MP na hora."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pix":{"type":"string","enum":["sim","nao","desconhecido"]},"cartao":{"type":"string","enum":["sim","nao","desconhecido"]},"boleto":{"type":"string","enum":["sim","nao","desconhecido"]},"fonte":{"type":"string","enum":["mercado_pago","cache","indisponivel"]},"verificado_em":{"type":"string","nullable":true},"erro":{"type":"string","nullable":true}}}}}}}}},"/internal/gateway-pagamento/mercado-pago/capacidades":{"get":{"summary":"Capacidades reais da conta Mercado Pago de um tenant (service-to-service)","tags":["Interno - Pagamentos"],"description":"Mesma resposta da rota autenticada, para a vitrine. Auth via header X-Internal-Key.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"boolean"},"in":"query","name":"forcar","required":false},{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true,"description":"Chave interna service-to-service"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"pix":{"type":"string","enum":["sim","nao","desconhecido"]},"cartao":{"type":"string","enum":["sim","nao","desconhecido"]},"boleto":{"type":"string","enum":["sim","nao","desconhecido"]},"fonte":{"type":"string","enum":["mercado_pago","cache","indisponivel"]},"verificado_em":{"type":"string","nullable":true},"erro":{"type":"string","nullable":true}}}}}}}}},"/gateway-pagamento/mercado-pago/regras-parcelamento":{"patch":{"summary":"Configurar regras de parcelamento do Mercado Pago","tags":["Pagamentos - Mercado Pago"],"description":"Define máximo de parcelas e valor mínimo por parcela (centavos). Aplicado pelo dispatcher antes de criar pagamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"max_parcelas":{"type":"integer","minimum":1,"maximum":24,"nullable":true},"valor_minimo_parcela_centavos":{"type":"integer","minimum":0,"nullable":true},"parcelas_sem_juros":{"type":"integer","minimum":0,"maximum":24,"nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/webhook/mercado-pago/{accountId}":{"post":{"summary":"Receber webhook do Mercado Pago","tags":["Webhooks - Mercado Pago"],"description":"Rota pública com rate limit. Valida HMAC SHA-256 (x-signature). Consulta /v1/payments/{id} com access_token (refresh automático). Idempotência via gateway_webhook_events.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string"},"type":{"type":"string"},"data":{"type":"object","properties":{"id":{"type":"string"}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/mercado-pago":{"post":{"summary":"Receber webhook do Mercado Pago (URL unica do painel)","tags":["Webhooks - Mercado Pago"],"description":"Rota publica cadastrada no painel da aplicacao MP. Resolve o tenant pelo user_id do vendedor (gravado no OAuth) e processa como a rota por tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string"},"type":{"type":"string"},"user_id":{},"data":{"type":"object","properties":{"id":{}}}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/gateway-pagamento/saude":{"get":{"summary":"Dashboard de saúde dos gateways de pagamento","tags":["Pagamentos - Saúde"],"description":"Retorna status agregado por provider: health-check, circuit breaker, webhooks últimas 24h e últimos erros.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"providers":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"circuit_state":{"type":"string","enum":["closed","open","half-open"]},"ultimas_24h":{"type":"object","properties":{"total":{"type":"integer"},"processados":{"type":"integer"},"falhados":{"type":"integer"},"dead_letters":{"type":"integer"}}},"ultimos_erros":{"type":"array","items":{"type":"object","properties":{"event_id":{"type":"string"},"event_type":{"type":"string","nullable":true},"error":{"type":"string"},"created_at":{"type":"string"}}}}}}}}}}}}}}},"/webhooks-registro/auditoria":{"get":{"summary":"Auditar o registro de webhook nos provedores","tags":["Pagamentos - Gateway"],"description":"Consulta a API do provedor, quando existe, e devolve o estado real de cada gateway: confirmado_na_fonte, divergente_na_fonte, nao_verificavel ou erro_ao_verificar. Somente leitura.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/webhooks-registro/reprovisionar":{"post":{"summary":"Reprovisionar o webhook nos provedores","tags":["Pagamentos - Gateway"],"description":"Re-registra a URL de webhook via API nos providers que suportam e devolve URL + instrução para os que exigem cadastro manual no painel. Exige APP_URL configurada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Limita a operação a um provider. Sem ele, todos os do tenant."}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/sales-channels/{provider}/connect":{"post":{"summary":"Iniciar fluxo OAuth com Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"Retorna authorize_url assinado com state HMAC + binding de tenant (TTL 15min). Lojista deve ser redirecionado pra essa URL.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"},"aviso_estoque":{"type":"string","nullable":true}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"envs_faltando":{"type":"array","items":{"type":"string"}}}}}}}}}},"/sales-channels/{provider}/callback":{"post":{"summary":"Callback OAuth Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"Recebe code+state do redirect ML, valida state HMAC, troca por access_token+refresh_token e persiste em sales_channels.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"additionalProperties":false,"properties":{"code":{"type":"string","description":"Authorization code retornado pelo ML"},"state":{"type":"string","description":"State HMAC pra anti-CSRF"}}}}},"required":true},"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string","nullable":true},"external_user_id":{"type":"string","nullable":true},"site_id":{"type":"string"}}}}}}}}},"/sales-channels/{provider}/status":{"get":{"summary":"Status da conexão Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"gestor_de_estoque":{"type":"string"},"gestor_de_estoque_aviso":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/{provider}/health-check":{"post":{"summary":"Validar credenciais com GET /users/me","tags":["Canais de Venda - Mercado Livre"],"description":"Faz refresh se preciso, chama GET /users/me, atualiza status + last_health_check_at + last_health_error.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"},"last_health_check_at":{"type":"string"},"last_health_error":{"type":"string","nullable":true},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/{provider}/config":{"patch":{"summary":"Configurar regras do canal","tags":["Canais de Venda - Mercado Livre"],"description":"Markup global, buffer de segurança, quem gerencia o saldo deste canal e o liga/desliga. Os depósitos do canal NÃO ficam aqui: são linhas de `canal_locais`, em PUT /sales-channels/mercado-livre/locais (D-19). Modo de frete e tipo de anúncio saíram no P2-15 — eram gravados e nunca lidos. Chave desconhecida no corpo é IGNORADA (o schema não é estrito), então um web antigo mandando `frete_modo` não quebra: o valor só deixa de ser gravado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"gestor_saldo":{"type":"string","nullable":true},"ativo":{"type":"boolean","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/{provider}/locais":{"get":{"summary":"Depósitos de onde o canal publica e reserva","tags":["Canais de Venda - Mercado Livre"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"origem":{"type":"string","enum":["canal_locais","despacho_do_tenant","estoque_do_tenant","nenhum"]},"locais":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"prioridade":{"type":"number"}}}}}}}}}}},"put":{"summary":"Definir os depósitos do canal (substitui o conjunto)","tags":["Canais de Venda - Mercado Livre"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"vinculados":{"type":"integer"}}}}}}}}},"/sales-channels/{provider}/saude":{"get":{"summary":"Saúde operacional do canal Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"Agrega estado do circuit breaker outbound, estatísticas de webhooks das últimas 24h, anúncios com erro de sync e pedidos com status ML desconhecido. Usado pela tela de saúde do canal no admin.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"circuit_state":{"type":"string","enum":["closed","open","half-open"]},"ultimas_24h":{"type":"object","properties":{"webhooks_recebidos":{"type":"integer"},"processados":{"type":"integer"},"com_erro":{"type":"integer"},"eventos_decididos":{"type":"integer"},"eventos_sem_handler":{"type":"integer"},"dead_letters":{"type":"integer"},"eventos_desistidos":{"type":"integer"}}},"listings_sync_error":{"type":"integer"},"pedidos_status_desconhecido":{"type":"integer"},"pedidos_itens_sem_vinculo":{"type":"integer"},"itens_sem_vinculo_truncado":{"type":"boolean"},"pedidos_estoque_pendente":{"type":"integer"},"pedidos_devolucao_pendente":{"type":"integer"},"skus_saldo_negativo":{"type":"integer"},"pedidos_presos":{"type":"integer"},"pedidos_presos_link":{"type":"string","nullable":true},"pedidos_presos_lista":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"numero":{"type":"string","nullable":true}}}},"itens_sem_vinculo_link":{"type":"string","nullable":true},"itens_sem_vinculo_mlbs":{"type":"array","items":{"type":"string"}},"canal":{"type":"object","nullable":true,"properties":{"status":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"ultimo_webhook_at":{"type":"string","nullable":true},"resgate_ultima_rodada":{"type":"object","nullable":true,"additionalProperties":true}}}}}}}}}}},"/sales-channels/{provider}/disconnect":{"post":{"summary":"Desconectar Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"Revoga a autorização da aplicação na conta do Mercado Livre (best-effort), apaga os tokens e marca o canal como desconectado. Os vínculos de anúncios, os ajustes de preço e o histórico de pedidos são PRESERVADOS — reconectar restaura tudo. Anúncios continuam no ML (não pausamos automaticamente).","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"provider","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"revogacao_erro":{"type":"string","nullable":true},"vinculos_preservados":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/liberacao":{"get":{"summary":"A Shopee está liberada para este lojista?","tags":["Canais de Venda - Shopee"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/connect":{"post":{"summary":"Iniciar a autorização da loja Shopee","tags":["Canais de Venda - Shopee"],"description":"Devolve authorize_url (página de consentimento da Shopee da região do vendedor, com state HMAC de 15 min e uso único) e o redirect_uri, que é a página de retorno do web.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/shopee/callback":{"post":{"summary":"Concluir a autorização da loja Shopee","tags":["Canais de Venda - Shopee"],"description":"Recebe code + state e exatamente um de shop_id (conta de loja) ou main_account_id (conta principal), troca pelo par de tokens e grava a loja em sales_channels. 409 shopee_uma_loja quando a conta já tem uma loja da Shopee ou a conta principal reúne várias. Outra loja no lugar da desconectada remove os vínculos de anúncio da loja anterior (vinculos_removidos).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"additionalProperties":false,"properties":{"code":{"type":"string","minLength":1,"description":"Código de uso único do redirect (10 min)."},"state":{"type":"string","minLength":1,"description":"State HMAC devolvido pela Shopee."},"shop_id":{"type":"string","description":"Autorização por conta de loja."},"main_account_id":{"type":"string","description":"Autorização por conta principal."}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string","nullable":true},"external_user_id":{"type":"string"},"region":{"type":"string","nullable":true},"vinculos_removidos":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/status":{"get":{"summary":"Status da conexão com a Shopee","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"tax_id_type":{"type":"integer","nullable":true},"shop_fulfillment_flag":{"type":"string","nullable":true},"auth_expire_time":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/health-check":{"post":{"summary":"Testar a conexão com a Shopee","tags":["Canais de Venda - Shopee"],"description":"Resolve o token (renovando se preciso), lê get_shop_info e atualiza o estado da conexão.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/saude":{"get":{"summary":"Saúde operacional do canal Shopee","tags":["Canais de Venda - Shopee"],"description":"Circuito de saída, eventos de push das últimas 24 h, anúncios com erro de sincronização, pedidos com status fora do mapa, estoque pendente e pedidos em IN_CANCEL (o comprador pediu cancelamento e quem responde é a loja).","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"circuit_state":{"type":"string","enum":["closed","open","half-open"]},"ultimas_24h":{"type":"object","properties":{"webhooks_recebidos":{"type":"integer"},"processados":{"type":"integer"},"com_erro":{"type":"integer"},"eventos_decididos":{"type":"integer"},"eventos_sem_handler":{"type":"integer"},"dead_letters":{"type":"integer"},"eventos_desistidos":{"type":"integer"}}},"listings_sync_error":{"type":"integer"},"pedidos_status_desconhecido":{"type":"integer"},"pedidos_estoque_pendente":{"type":"integer"},"pedidos_cancelamento_a_responder":{"type":"integer"},"canal":{"type":"object","nullable":true,"properties":{"status":{"type":"string","nullable":true},"expires_at":{"type":"string","nullable":true},"auth_expire_time":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"ultimo_webhook_at":{"type":"string","nullable":true}}}}}}}}}}},"/sales-channels/shopee/config":{"patch":{"summary":"Ligar/pausar a Shopee e gravar as regras do canal","tags":["Canais de Venda - Shopee"],"description":"Mesmo contrato do PATCH /sales-channels/mercado-livre/config para ativo, markup_percentual, buffer_seguranca, margem_liquida_percentual e custo_operacao_centavos. Ativar exige a conexão em ok. Com mais de uma loja conectada, informe ?shop_id=.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"ativo":{"type":"boolean","nullable":true},"etiqueta_formato":{"type":"string","enum":["a4","termica",null],"nullable":true}}}}}},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/shopee/disconnect":{"post":{"summary":"Desconectar a loja Shopee","tags":["Canais de Venda - Shopee"],"description":"Apaga os tokens, marca o canal como desconectado e invalida o roteamento do push. Vínculos, régua e histórico são preservados (os vínculos saem se outra loja for conectada no lugar). Com mais de uma loja conectada, informe ?shop_id=.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"vinculos_preservados":{"type":"integer"},"shop_id":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/locais":{"get":{"summary":"Depósitos de onde a Shopee publica e reserva","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"origem":{"type":"string","enum":["canal_locais","despacho_do_tenant","estoque_do_tenant","nenhum"]},"locais":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"prioridade":{"type":"number"}}}}}}}}}}},"put":{"summary":"Definir os depósitos da Shopee (substitui o conjunto)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"vinculados":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/listings":{"get":{"summary":"Anúncios da loja na Shopee, por variação, com vínculo, sugestão por SKU e divergências","tags":["Canais de Venda - Shopee"],"description":"`total` conta os ANÚNCIOS que casam com o filtro; `contagem` conta as VARIAÇÕES por situação na loja inteira. `busca` casa nome ou SKU (do anúncio ou do modelo). O catálogo da Shopee fica 5 minutos em cache, e o que a Varejo Hub enviou (ou o vínculo acabou de enfileirar) vale sobre ele; vínculo, sugestão, preço e estoque da Varejo Hub são calculados a cada pedido. `estoque_hub` nulo numa variação vinculada = a Shopee não tem depósito de onde publicar (o aviso vem em `ultimo_erro`). Variação que o vínculo sempre recusaria (vários armazéns, banido) não tem `sugestao` e, sem vínculo, conta em `bloqueados` (filtro `situacao=bloqueados`), e não em `sem_produto`.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","enum":["todas","vinculados","sugeridos","sem_produto","bloqueados","divergentes"],"default":"todas"},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true},"status":{"type":"string"},"url":{"type":"string","nullable":true},"promocao_ativa":{"type":"boolean"},"variacoes":{"type":"array","items":{"type":"object","properties":{"model_id":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"preco_canal_centavos":{"type":"integer","nullable":true},"estoque_canal":{"type":"integer","nullable":true},"vinculo":{"type":"object","nullable":true,"properties":{"listing_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"produto_nome":{"type":"string"},"variacao_nome":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true}}},"sugestao":{"type":"object","nullable":true,"properties":{"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"produto_nome":{"type":"string"},"sku":{"type":"string"}}},"preco_hub_centavos":{"type":"integer","nullable":true},"preco_proprio_centavos":{"type":"integer","nullable":true},"preco_produto_centavos":{"type":"integer","nullable":true},"estoque_hub":{"type":"integer","nullable":true},"divergencia":{"type":"object","nullable":true,"properties":{"preco":{"type":"boolean"},"estoque":{"type":"boolean"}}},"bloqueio":{"type":"string","nullable":true,"enum":["varios_armazens","promocao_trava_preco","anuncio_banido",null]},"ultimo_erro":{"type":"string","nullable":true}}}}}}},"total":{"type":"integer"},"pagina":{"type":"integer"},"por_pagina":{"type":"integer"},"contagem":{"type":"object","properties":{"vinculados":{"type":"integer"},"sugeridos":{"type":"integer"},"sem_produto":{"type":"integer"},"bloqueados":{"type":"integer"},"divergentes":{"type":"integer"}}}}}}}}}}},"/sales-channels/shopee/listings/vincular":{"post":{"summary":"Vincular variações da Shopee a produtos da Varejo Hub (manual ou por SKU)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"itens":{"type":"array","minItems":1,"maxItems":500,"items":{"type":"object","required":["item_id","produto_id"],"properties":{"item_id":{"type":"string","minLength":1},"model_id":{"type":"string","nullable":true},"produto_id":{"type":"string","minLength":1},"variacao_id":{"type":"string","nullable":true}}}},"automatico_por_sku":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"vinculados":{"type":"integer"},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/listings/{listingId}/sync":{"post":{"summary":"Enviar agora o preço e o estoque de uma variação vinculada","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"listingId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"preco":{"type":"string","enum":["enviado","travado","erro"]},"estoque":{"type":"string","enum":["enviado","erro"]},"erro":{"type":"string"}}}}}}}}},"/sales-channels/shopee/listings/{listingId}/preco-proprio":{"patch":{"summary":"Fixar ou tirar o preço próprio de uma variação vinculada (null segue o preço da Varejo Hub)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["preco_proprio_centavos"],"additionalProperties":false,"properties":{"preco_proprio_centavos":{"type":["integer","null"],"minimum":1}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"listingId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"preco":{"type":"string","enum":["enviado","travado","erro","nao_envia"]},"erro":{"type":"string"}}}}}}}}},"/sales-channels/shopee/listings/{listingId}":{"delete":{"summary":"Desvincular uma variação da Shopee","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"listingId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/shopee/comissao":{"get":{"summary":"Comissão da Shopee para um preço, pela tabela BR publicada","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"integer","minimum":1},"in":"query","name":"preco_centavos","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"percentual":{"type":"number"},"taxa_fixa_centavos":{"type":"integer"},"fonte":{"type":"string","enum":["tabela_shopee_br"]},"vigencia":{"type":"string"},"tipo_documento":{"type":"string","nullable":true,"enum":["cnpj","cpf",null]}}}}}}}}},"/sales-channels/shopee/publicacao/produtos":{"get":{"summary":"Produtos ativos da Varejo Hub para publicar na Shopee, com o preço e o estoque que ela receberia","tags":["Canais de Venda - Shopee"],"description":"Os publicados nesta loja vêm marcados (`ja_publicado`) em vez de escondidos: escondê-los por `not.in` estoura a URL do PostgREST com centenas de anúncios. `estoque` nulo = a Shopee não tem depósito de onde publicar (aba Regras). `busca` casa nome ou SKU.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"produtos":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"variacoes":{"type":"integer"},"preco_centavos":{"type":"integer","nullable":true},"estoque":{"type":"integer","nullable":true},"ja_publicado":{"type":"boolean"}}}},"total":{"type":"integer"},"pagina":{"type":"integer"},"por_pagina":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/publicacao/preparar/{produtoId}":{"get":{"summary":"Tudo o que a tela de publicar precisa de um produto: grade, preço e estoque que a Shopee receberia, fretes e pendências","tags":["Canais de Venda - Shopee"],"description":"`modelos[].preco_centavos` 0 = sem preço (a pendência diz). `pendencias` traz o que é do produto e da loja; atributos, marca e limites da categoria são conferidos no envio.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"produto":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"descricao":{"type":"string"},"fotos":{"type":"array","items":{"type":"string"}},"peso_gramas":{"type":"number","nullable":true},"dimensoes_cm":{"type":"object","nullable":true,"properties":{"comprimento":{"type":"number"},"largura":{"type":"number"},"altura":{"type":"number"}}},"ncm":{"type":"string","nullable":true},"cest":{"type":"string","nullable":true},"origem_fiscal":{"type":"string","nullable":true},"marca":{"type":"string","nullable":true},"atributos":{"type":"object","additionalProperties":{"type":"string"}}}},"categoria_sugerida":{"type":"object","nullable":true,"properties":{"id":{"type":"integer"},"caminho":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["shopee","nome"]}}},"eixos":{"type":"array","items":{"type":"object","properties":{"nome":{"type":"string"},"opcoes":{"type":"array","items":{"type":"string"}}}}},"modelos":{"type":"array","items":{"type":"object","properties":{"variacao_id":{"type":"string","nullable":true},"opcoes":{"type":"array","items":{"type":"string"}},"sku":{"type":"string","nullable":true},"preco_centavos":{"type":"integer"},"estoque":{"type":"integer"}}}},"logistica":{"type":"array","items":{"type":"object","properties":{"logistic_id":{"type":"integer"},"nome":{"type":"string"},"habilitado":{"type":"boolean"},"tipo_frete":{"type":"string"},"peso_max_gramas":{"type":"integer","nullable":true}}}},"pendencias":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"publicacao_atual":{"type":"object","properties":{"situacao":{"type":"string","enum":["publicado","sem_variacoes","recusado","em_andamento","em_analise"]},"item_id":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"vinculados":{"type":"integer"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string","nullable":true},"mensagem":{"type":"string"}}}},"pode_descartar":{"type":"boolean","description":"Não deu para conferir na Shopee se a tentativa anterior criou o anúncio: a tela oferece descartar a tentativa."},"pode_corrigir":{"type":"boolean","description":"O anúncio existe na Shopee, foi criado aqui e não está à venda: a tela oferece corrigir e publicar de novo (`descartar-anuncio`)."}},"nullable":true,"description":"O anúncio que o produto já tem nesta loja (em análise, parado, à venda ou vinculado); `null` = nada criado ainda."}}}}}}}}},"/sales-channels/shopee/publicacao/categorias":{"get":{"summary":"A árvore de categorias da Shopee, um nível por vez (sem `pai`, a raiz)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"integer","minimum":0},"in":"query","name":"pai","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"categorias":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nome":{"type":"string"},"tem_filhos":{"type":"boolean"}}}}}}}}}}}},"/sales-channels/shopee/publicacao/categorias/sugestao":{"get":{"summary":"Categorias para o nome: a sugestão da Shopee primeiro, depois as achadas pelo nome na árvore em português, com o caminho de cada uma","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"query","name":"nome","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"categorias":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"caminho":{"type":"array","items":{"type":"string"}},"origem":{"type":"string","enum":["shopee","nome"]}}}}}}}}}}}},"/sales-channels/shopee/publicacao/categorias/{id}/atributos":{"get":{"summary":"Os atributos da categoria (obrigatórios, tipo, unidade, valores e dependentes)","tags":["Canais de Venda - Shopee"],"description":"Os dependentes vêm logo depois do atributo de quem dependem; só são exigidos quando ele tiver valor.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"integer","minimum":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nome":{"type":"string"},"obrigatorio":{"type":"boolean"},"tipo":{"type":"string","enum":["lista","texto","numero","data","multi"]},"aceita_texto":{"type":"boolean","description":"Aceita valor digitado (`valor_id: 0` + `valor_texto`) além da lista."},"unidade":{"type":"string","nullable":true},"valores":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nome":{"type":"string"}}}},"dependentes":{"type":"array","items":{"type":"integer"}}}}}}}}}}},"/sales-channels/shopee/publicacao/categorias/{id}/marcas":{"get":{"summary":"As marcas da Shopee para a categoria, e se a marca é obrigatória (0 = sem marca)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","maxLength":100},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"marcas":{"type":"array","items":{"type":"object","properties":{"id":{"type":"integer"},"nome":{"type":"string"}}}},"obrigatoria":{"type":"boolean"}}}}}}}}},"/sales-channels/shopee/publicacao/categorias/{id}/limites":{"get":{"summary":"Os limites de anúncio da categoria (nome, fotos, descrição, peso, medidas e preço)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"integer","minimum":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"nome_max":{"type":"integer"},"imagens_max":{"type":"integer"},"descricao_max":{"type":"integer"},"peso_obrigatorio":{"type":"boolean"},"dimensoes_obrigatorias":{"type":"boolean"},"preco_min_centavos":{"type":"integer","nullable":true},"preco_max_centavos":{"type":"integer","nullable":true}}}}}}}}},"/sales-channels/shopee/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub na Shopee (idempotente por produto e loja)","tags":["Canais de Venda - Shopee"],"description":"Cria o anúncio não listado, espera 5 s, cria as variações (estrutura padronizada), grava uma linha de vínculo por variação e só então lista. `sem_variacoes`: o anúncio existe e está não listado; `/publicar/:itemId/retomar-variacoes` termina o que faltou. O segundo clique devolve o que está em andamento ou pronto, sem criar outro anúncio.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["produto_id","categoria_id","marca_id","atributos","logistica","condicao"],"properties":{"produto_id":{"type":"string","minLength":1},"categoria_id":{"type":"integer","minimum":1},"marca_id":{"type":"integer","minimum":0},"atributos":{"type":"array","maxItems":200,"items":{"type":"object","additionalProperties":false,"required":["id","valor_id"],"properties":{"id":{"type":"integer","minimum":1},"valor_id":{"type":"integer","minimum":0},"valor_texto":{"type":"string","maxLength":500},"unidade":{"type":"string","maxLength":50}}}},"logistica":{"type":"array","maxItems":50,"items":{"type":"integer","minimum":1}},"titulo":{"type":"string","maxLength":300},"descricao":{"type":"string","maxLength":20000},"condicao":{"type":"string","enum":["NEW","USED"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["publicado","sem_variacoes","recusado","em_andamento","em_analise"]},"item_id":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"vinculados":{"type":"integer"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string","nullable":true},"mensagem":{"type":"string"}}}},"pode_descartar":{"type":"boolean","description":"Não deu para conferir na Shopee se a tentativa anterior criou o anúncio: a tela oferece descartar a tentativa."},"pode_corrigir":{"type":"boolean","description":"O anúncio existe na Shopee, foi criado aqui e não está à venda: a tela oferece corrigir e publicar de novo (`descartar-anuncio`)."}}}}}}}}},"/sales-channels/shopee/publicar/{itemId}/retomar-variacoes":{"post":{"summary":"Terminar a publicação de um anúncio que ficou não listado (variações, vínculos e listagem)","tags":["Canais de Venda - Shopee"],"description":"A grade, o preço e o estoque são os de agora. 404 = o item não foi publicado por esta loja.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,20}$"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["publicado","sem_variacoes","recusado","em_andamento","em_analise"]},"item_id":{"type":"string","nullable":true},"url":{"type":"string","nullable":true},"vinculados":{"type":"integer"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string","nullable":true},"mensagem":{"type":"string"}}}},"pode_descartar":{"type":"boolean","description":"Não deu para conferir na Shopee se a tentativa anterior criou o anúncio: a tela oferece descartar a tentativa."},"pode_corrigir":{"type":"boolean","description":"O anúncio existe na Shopee, foi criado aqui e não está à venda: a tela oferece corrigir e publicar de novo (`descartar-anuncio`)."}}}}}}}}},"/sales-channels/shopee/publicar/{itemId}/descartar-anuncio":{"post":{"summary":"Excluir na Shopee o anúncio criado aqui que não está à venda, para publicar de novo com outra marca ou categoria","tags":["Canais de Venda - Shopee"],"description":"Só anúncio criado pela Varejo Hub (`origem = publicacao`) e não listado; o resto responde `a_venda` com o motivo em `erro`. `sem_anuncio` = o item não é desta loja (ou já saiu). A recusa da Shopee volta em `erro`, em português.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,20}$"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"descartado":{"type":"boolean"},"situacao":{"type":"string","enum":["descartado","sem_anuncio","a_venda","em_andamento","nao_excluido"]},"erro":{"type":"string"}}}}}}}}},"/sales-channels/shopee/publicacao/produtos/{produtoId}/descartar-tentativa":{"post":{"summary":"Descartar a tentativa de publicação sem anúncio conhecido (o produto volta a ser publicável)","tags":["Canais de Venda - Shopee"],"description":"Idempotente: sem tentativa a descartar, `descartado: false` com `sem_tentativa`. Não apaga o rascunho que já sabe o item (esse se retoma), nem o envio em curso (`em_andamento`). Se a Shopee tiver criado o anúncio, ele segue não listado no Seller Center.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"descartado":{"type":"boolean"},"situacao":{"type":"string","enum":["descartado","sem_tentativa","em_andamento"]}}}}}}}}},"/sales-channels/shopee/publicacao/titulo/sugestoes":{"post":{"summary":"Até 3 títulos sugeridos por IA para o anúncio da Shopee, já dentro das regras de título do canal","tags":["Canais de Venda - Shopee"],"description":"Nunca troca o título: a tela mostra as sugestões e a pessoa escolhe. 429 = a loja passou do teto diário (`TITULO_IA_LIMITE_DIA`, padrão 30); 503 = nenhum modelo da cadeia respondeu. As duas trazem a frase da tela.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"additionalProperties":false,"properties":{"produto_id":{"type":"string","maxLength":36},"categoria_id":{"type":"integer","minimum":1,"nullable":true},"categoria_caminho":{"type":"array","maxItems":8,"items":{"type":"string","maxLength":120}},"marca":{"type":"string","maxLength":120,"nullable":true},"atributos":{"type":"array","maxItems":40,"items":{"type":"object","required":["nome","valor"],"properties":{"nome":{"type":"string","maxLength":80},"valor":{"type":"string","maxLength":200}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sugestoes":{"type":"array","items":{"type":"object","properties":{"titulo":{"type":"string"},"caracteres":{"type":"integer"}}}},"limite_caracteres":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/saude-da-conta":{"get":{"summary":"Saúde da conta na Shopee: nota, métricas com meta, pontos, punições, anúncios com problema e pedidos atrasados","tags":["Canais de Venda - Shopee"],"description":"Lê os 6 endpoints `v2.account_health.*` (5 aqui, o 6º no detalhe da métrica). Cache de 15 minutos por loja; `atualizar=true` ignora o cache. Uma leitura que falha não derruba as outras: a seção vem vazia e o motivo vem em `erros` com o `campo` da seção. O push 28 da Shopee limpa o cache.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"boolean"},"in":"query","name":"atualizar","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/sales-channels/shopee/saude-da-conta/metricas/{metricId}":{"get":{"summary":"Pedidos ou anúncios que puxaram uma métrica da saúde da conta (`get_metric_source_detail`)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"integer","minimum":1},"in":"path","name":"metricId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}":{"get":{"summary":"Devolução da Shopee: prazos, solução, valor, provas do comprador, ações disponíveis e faixa de oferta","tags":["Canais de Venda - Shopee"],"description":"Lê `get_return_detail` e `get_available_solutions` na hora (sem cache: prazo e negociação mudam). `acoes` diz o que a loja pode fazer agora; `faixa_de_oferta` é a da solução que a oferta usa (`solucao_da_oferta`).","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}/aceitar":{"post":{"summary":"Aceitar o reembolso da devolução (`v2.returns.confirm`), só na devolução de só reembolso","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["feito","falhou"]},"erros":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}/aceitar-oferta":{"post":{"summary":"Aceitar a proposta do comprador (`v2.returns.accept_offer`)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["feito","falhou"]},"erros":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}/oferecer":{"post":{"summary":"Oferecer reembolso parcial dentro da faixa da Shopee (`v2.returns.offer`)","tags":["Canais de Venda - Shopee"],"description":"A faixa e a solução vêm de `get_available_solutions`, relida na hora; valor fora dela volta `falhou` sem chamar a Shopee.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["valor_centavos"],"additionalProperties":false,"properties":{"valor_centavos":{"type":"integer","minimum":1}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["feito","falhou"]},"erros":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}/motivos-de-contestacao":{"get":{"summary":"Motivos de contestação e as provas que cada um pede (`v2.returns.get_return_dispute_reason`)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/sales-channels/shopee/devolucoes/{devolucaoId}/contestar":{"post":{"summary":"Contestar a devolução com motivo e fotos (`convert_image` + `v2.returns.dispute`)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"situacao":{"type":"string","enum":["feito","falhou"]},"erros":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/sales-channels/shopee/pedidos/{pedidoId}/despacho":{"get":{"summary":"Despacho do pedido da Shopee: prazo, nota fiscal, pacotes, etiqueta e cancelamento","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/nota-fiscal":{"post":{"summary":"Envia a NF-e do pedido à Shopee (XML anexado ou a nota do pedido), com pré-checagem","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/envio/opcoes":{"get":{"summary":"Coleta ou postagem do pacote: endereços, horários (com o recomendado) e agências","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string"},"in":"query","name":"package_number","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/envio":{"post":{"summary":"Organiza o envio do pacote na Shopee (ship_order)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["package_number","modo"],"properties":{"package_number":{"type":"string","minLength":1},"modo":{"type":"string","enum":["coleta","postagem"]},"address_id":{"type":"integer"},"pickup_time_id":{"type":"string"},"branch_id":{"type":"integer"}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/etiqueta":{"post":{"summary":"Pede a etiqueta oficial da Shopee do pacote (A4 ou térmica)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["package_number"],"properties":{"package_number":{"type":"string","minLength":1},"formato":{"type":"string","enum":["a4","termica"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"Situação da etiqueta do pacote e o link assinado quando pronta","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string"},"in":"query","name":"package_number","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/cancelamento":{"post":{"summary":"Aceita ou recusa o cancelamento pedido pelo comprador (handle_buyer_cancellation)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["decisao"],"properties":{"decisao":{"type":"string","enum":["aceitar","recusar"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/pedidos/{pedidoId}/cancelar":{"post":{"summary":"Cancela o pedido por falta de estoque (cancel_order OUT_OF_STOCK); conta contra a loja na Shopee","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo","itens"],"properties":{"motivo":{"type":"string","enum":["sem_estoque"]},"itens":{"type":"array","items":{"type":"object","required":["item_id","model_id"],"properties":{"item_id":{"type":"string"},"model_id":{"type":"string"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/envio-em-lote/opcoes":{"get":{"summary":"Coleta ou postagem para um lote de pedidos (do primeiro grupo de canal e armazém)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string"},"in":"query","name":"pedido_ids","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/envio-em-lote":{"post":{"summary":"Organiza o envio de vários pedidos (mass_ship_order por canal logístico e armazém)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids","modo"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"modo":{"type":"string","enum":["coleta","postagem"]},"address_id":{"type":"integer"},"pickup_time_id":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/etiquetas-em-lote":{"post":{"summary":"Etiquetas de vários pedidos num arquivo só (idempotente: repita enquanto vier gerando)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"formato":{"type":"string","enum":["a4","termica"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"A espera das etiquetas do lote: consulta só o resultado das já pedidas, sem reler nem regravar os pedidos","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false},{"schema":{"type":"string"},"in":"query","name":"pedido_ids","required":true},{"schema":{"type":"string","enum":["a4","termica"]},"in":"query","name":"formato","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shopee/avaliacoes":{"get":{"summary":"Avaliações dos anúncios da loja na Shopee, com os filtros da aba","tags":["Canais de Venda - Shopee"],"description":"Lidas do banco: a rotina de 30 minutos (ou `POST .../ler`) traz da Shopee as avaliações dos anúncios cujo `comment_count` mudou. `contagem`, `por_nota` e `nota_media` são da loja inteira, sem filtro. `busca` casa o texto, o comprador, o número do pedido e o nome do anúncio.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","enum":["todas","sem_resposta","respondidas","com_midia"],"default":"todas"},"in":"query","name":"situacao","required":false},{"schema":{"type":"integer","minimum":1,"maximum":5},"in":"query","name":"nota","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"avaliacoes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"comment_id":{"type":"string"},"item_id":{"type":"string"},"anuncio_nome":{"type":"string","nullable":true},"anuncio_foto_url":{"type":"string","nullable":true},"model_ids":{"type":"array","items":{"type":"string"}},"order_sn":{"type":"string","nullable":true},"pedido_id":{"type":"string","nullable":true},"pedido_numero":{"type":"string","nullable":true},"produto_id":{"type":"string","nullable":true},"produto_nome":{"type":"string","nullable":true},"nota":{"type":"integer"},"texto":{"type":"string","nullable":true},"imagens":{"type":"array","items":{"type":"string"}},"videos":{"type":"array","items":{"type":"string"}},"comprador":{"type":"string","nullable":true},"criada_em":{"type":"string"},"oculta":{"type":"boolean"},"situacao":{"type":"string","enum":["sem_resposta","enviando","respondida","falhou"]},"resposta":{"type":"string","nullable":true},"respondida_em":{"type":"string","nullable":true},"resposta_erro":{"type":"string","nullable":true},"sugestao_ia":{"type":"string","nullable":true},"sugestao_ia_em":{"type":"string","nullable":true}}}},"total":{"type":"integer"},"pagina":{"type":"integer"},"por_pagina":{"type":"integer"},"contagem":{"type":"object","properties":{"todas":{"type":"integer"},"sem_resposta":{"type":"integer"},"respondidas":{"type":"integer"},"com_midia":{"type":"integer"}}},"por_nota":{"type":"object","properties":{"1":{"type":"integer"},"2":{"type":"integer"},"3":{"type":"integer"},"4":{"type":"integer"},"5":{"type":"integer"}}},"nota_media":{"type":"number","nullable":true},"ultima_leitura_em":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/avaliacoes/resumo":{"get":{"summary":"Quantas avaliações estão sem resposta e a nota média (visão geral do canal)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"integer"},"sem_resposta":{"type":"integer"},"nota_media":{"type":"number","nullable":true},"ultima_leitura_em":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shopee/avaliacoes/ler":{"post":{"summary":"Ler agora as avaliações novas da Shopee","tags":["Canais de Venda - Shopee"],"description":"Espera até 20 s; passou disso, responde `em_andamento` e a leitura termina em segundo plano.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"em_andamento":{"type":"boolean"},"anuncios":{"type":"integer"},"mudaram":{"type":"integer"},"lidos":{"type":"integer"},"avaliacoes":{"type":"integer"},"pendentes":{"type":"integer"},"falhas":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/avaliacoes/{id}/sugestao":{"post":{"summary":"Sugerir com IA a resposta de uma avaliação (só o rascunho; nada é enviado)","tags":["Canais de Venda - Shopee"],"description":"Relê a avaliação na Shopee antes de cobrar (respondida fora daqui: 409 sem débito). Uma geração por avaliação de cada vez (409 `em_andamento`). Debita a ação `resposta_avaliacao` dos Créditos IA; se o modelo ou a gravação falhar, os créditos voltam.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sugestao":{"type":"string"},"creditos":{"type":"integer"},"avaliacao_atualizada":{"type":"boolean"}}}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"necessario":{"type":"integer"},"disponivel":{"type":"integer"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"necessario":{"type":"integer"},"disponivel":{"type":"integer"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"necessario":{"type":"integer"},"disponivel":{"type":"integer"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"necessario":{"type":"integer"},"disponivel":{"type":"integer"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"necessario":{"type":"integer"},"disponivel":{"type":"integer"}}}}}}}},"delete":{"summary":"Descartar a sugestão da IA","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/shopee/avaliacoes/responder":{"post":{"summary":"Enviar a resposta de avaliações (única na Shopee, sem edição depois)","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["respostas"],"additionalProperties":false,"properties":{"respostas":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["id","texto"],"additionalProperties":false,"properties":{"id":{"type":"string","minLength":1},"texto":{"type":"string","maxLength":700}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"resultados":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"situacao":{"type":"string","enum":["respondida","ja_respondida","avaliacao_mudou","falhou","invalida","nao_encontrada","em_envio"]},"resposta":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes":{"get":{"summary":"Descontos e cupons da loja na Shopee (agendados, em andamento e encerrados)","tags":["Canais de Venda - Shopee"],"description":"Lido da Shopee com cache de 60 s (`atualizar=1` relê). `contagem` respeita `tipo` e `busca` e não a `situacao`. `anuncios` do desconto é contado nos descontos da página (cache de 5 min por desconto). Pedido mínimo, teto, exibição e anúncios do cupom vêm do `get_voucher` (cache de 5 min); `null` quando não deu para ler.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","enum":["todos","desconto","cupom"],"default":"todos"},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","enum":["todas","em_andamento","agendada","encerrada"],"default":"todas"},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false},{"schema":{"type":"string","enum":["0","1"]},"in":"query","name":"atualizar","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"promocoes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"id":{"type":"string"},"nome":{"type":"string"},"situacao":{"type":"string"},"inicio":{"type":"string"},"fim":{"type":"string"},"origem":{"type":"string"},"pode_encerrar":{"type":"boolean"},"pode_apagar":{"type":"boolean"},"anuncios":{"type":"integer","nullable":true},"cupom":{"type":"object","nullable":true,"properties":{"codigo":{"type":"string"},"escopo":{"type":"string"},"tipo_desconto":{"type":"string"},"valor_centavos":{"type":"integer","nullable":true},"percentual":{"type":"number","nullable":true},"desconto_maximo_centavos":{"type":"integer","nullable":true},"pedido_minimo_centavos":{"type":"integer","nullable":true},"quantidade":{"type":"integer"},"usados":{"type":"integer"},"exibicao":{"type":"string","nullable":true}}}}}},"total":{"type":"integer"},"pagina":{"type":"integer"},"por_pagina":{"type":"integer"},"contagem":{"type":"object","properties":{"todas":{"type":"integer"},"em_andamento":{"type":"integer"},"agendadas":{"type":"integer"},"encerradas":{"type":"integer"}}},"lido_em":{"type":"string"},"truncado":{"type":"boolean"}}}}}}}}},"/sales-channels/shopee/promocoes/descontos/{id}":{"get":{"summary":"Um desconto da Shopee com os anúncios e o preço de/por de cada variação","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"promocao":{"type":"object","properties":{"tipo":{"type":"string"},"id":{"type":"string"},"nome":{"type":"string"},"situacao":{"type":"string"},"inicio":{"type":"string"},"fim":{"type":"string"},"origem":{"type":"string"},"pode_encerrar":{"type":"boolean"},"pode_apagar":{"type":"boolean"},"anuncios":{"type":"integer","nullable":true},"cupom":{"type":"object","nullable":true,"properties":{"codigo":{"type":"string"},"escopo":{"type":"string"},"tipo_desconto":{"type":"string"},"valor_centavos":{"type":"integer","nullable":true},"percentual":{"type":"number","nullable":true},"desconto_maximo_centavos":{"type":"integer","nullable":true},"pedido_minimo_centavos":{"type":"integer","nullable":true},"quantidade":{"type":"integer"},"usados":{"type":"integer"},"exibicao":{"type":"string","nullable":true}}}}},"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true},"limite_por_comprador":{"type":"integer"},"variacoes":{"type":"array","items":{"type":"object","properties":{"model_id":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true},"preco_original_centavos":{"type":"integer","nullable":true},"preco_promocional_centavos":{"type":"integer","nullable":true},"estoque":{"type":"integer","nullable":true}}}}}}}}}}}}}},"delete":{"summary":"Apagar um desconto agendado","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes/cupons/{id}":{"get":{"summary":"Um cupom da loja na Shopee, com os anúncios do cupom de produtos","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"promocao":{"type":"object","properties":{"tipo":{"type":"string"},"id":{"type":"string"},"nome":{"type":"string"},"situacao":{"type":"string"},"inicio":{"type":"string"},"fim":{"type":"string"},"origem":{"type":"string"},"pode_encerrar":{"type":"boolean"},"pode_apagar":{"type":"boolean"},"anuncios":{"type":"integer","nullable":true},"cupom":{"type":"object","nullable":true,"properties":{"codigo":{"type":"string"},"escopo":{"type":"string"},"tipo_desconto":{"type":"string"},"valor_centavos":{"type":"integer","nullable":true},"percentual":{"type":"number","nullable":true},"desconto_maximo_centavos":{"type":"integer","nullable":true},"pedido_minimo_centavos":{"type":"integer","nullable":true},"quantidade":{"type":"integer"},"usados":{"type":"integer"},"exibicao":{"type":"string","nullable":true}}}}},"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true}}}}}}}}}}},"delete":{"summary":"Apagar um cupom agendado","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes/anuncios":{"get":{"summary":"Anúncios ativos para escolher no desconto ou no cupom, com o custo do produto vinculado","tags":["Canais de Venda - Shopee"],"description":"Só anúncios `NORMAL` (a Shopee recusa promoção em anúncio fora do ar). `promocoes` traz as promoções em que o anúncio já está (2 min de cache).","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"variacoes":{"type":"array","items":{"type":"object","properties":{"model_id":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"preco_centavos":{"type":"integer","nullable":true},"estoque":{"type":"integer","nullable":true},"vinculado":{"type":"boolean"},"custo_centavos":{"type":"integer","nullable":true},"produto_nome":{"type":"string","nullable":true}}}},"promocoes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"tipo_shopee":{"type":"string"},"promocao_id":{"type":"string"},"situacao":{"type":"string"},"inicio":{"type":"string"},"fim":{"type":"string"},"variacoes":{"type":"integer"},"preco_promocional_minimo_centavos":{"type":"integer","nullable":true}}}}}}},"total":{"type":"integer"},"pagina":{"type":"integer"},"por_pagina":{"type":"integer"}}}}}}}}},"/sales-channels/shopee/promocoes/selos":{"get":{"summary":"A promoção em andamento ou agendada de cada anúncio (selo da aba Anúncios)","tags":["Canais de Venda - Shopee"],"description":"Lido de `get_item_promotion`, com 2 min de cache por anúncio. Inclui campanhas da Shopee (10.10, 11.11, 12.12), que só se leem: a inscrição é no Seller Centre.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","maxLength":4000},"in":"query","name":"item_ids","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"promocoes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"tipo_shopee":{"type":"string"},"promocao_id":{"type":"string"},"situacao":{"type":"string"},"inicio":{"type":"string"},"fim":{"type":"string"},"variacoes":{"type":"integer"},"preco_promocional_minimo_centavos":{"type":"integer","nullable":true}}}}}}}}}}}}}}},"/sales-channels/shopee/promocoes/descontos/margem":{"post":{"summary":"Margem estimada no preço promocional, por variação","tags":["Canais de Venda - Shopee"],"description":"Comissão da tabela BR pelo documento da loja, custo do produto vinculado, custo de operação das regras do canal e frete médio pago pelo vendedor nos repasses da Shopee dos últimos 60 dias. Nada é gravado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["itens"],"additionalProperties":false,"properties":{"itens":{"type":"array","minItems":1,"maxItems":1000,"items":{"type":"object","required":["item_id","preco_promocional_centavos"],"properties":{"item_id":{"type":"string","minLength":1},"model_id":{"type":"string","nullable":true},"preco_promocional_centavos":{"type":"integer"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"preco_original_centavos":{"type":"integer","nullable":true},"preco_promocional_centavos":{"type":"integer"},"desconto_percentual":{"type":"number","nullable":true},"comissao_centavos":{"type":"integer","nullable":true},"repasse_centavos":{"type":"integer","nullable":true},"custo_centavos":{"type":"integer","nullable":true},"custo_operacao_centavos":{"type":"integer"},"frete_centavos":{"type":"integer"},"lucro_centavos":{"type":"integer","nullable":true},"margem_percentual":{"type":"number","nullable":true},"situacao":{"type":"string"},"explicacao":{"type":"string","nullable":true}}}},"frete":{"type":"object","properties":{"centavos":{"type":"integer"},"pedidos":{"type":"integer"}}},"tipo_documento":{"type":"string","nullable":true},"custo_operacao_centavos":{"type":"integer"},"margem_alvo_percentual":{"type":"number","nullable":true}}}}}}}}},"/sales-channels/shopee/promocoes/descontos":{"post":{"summary":"Criar um desconto de/por na Shopee com os anúncios e o preço promocional de cada variação","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","inicio","fim","itens"],"additionalProperties":false,"properties":{"nome":{"type":"string","maxLength":200},"inicio":{"type":"string"},"fim":{"type":"string"},"limite_por_comprador":{"type":"integer","default":0},"itens":{"type":"array","maxItems":5000,"items":{"type":"object","required":["item_id","preco_promocional_centavos"],"properties":{"item_id":{"type":"string","minLength":1},"model_id":{"type":"string","nullable":true},"preco_promocional_centavos":{"type":"integer"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string"},"adicionados":{"type":"integer"},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes/descontos/{id}/encerrar":{"post":{"summary":"Encerrar agora um desconto em andamento (o preço dos vinculados volta a sair da Varejo Hub)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes/cupons":{"post":{"summary":"Criar um cupom da loja na Shopee","tags":["Canais de Venda - Shopee"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","codigo","escopo","tipo_desconto","quantidade","inicio","fim","exibicao"],"additionalProperties":false,"properties":{"nome":{"type":"string","maxLength":200},"codigo":{"type":"string","maxLength":40},"escopo":{"type":"string","enum":["loja","produtos"]},"item_ids":{"type":"array","maxItems":1000,"items":{"type":"string"}},"tipo_desconto":{"type":"string","enum":["valor","percentual"]},"valor_centavos":{"type":"integer"},"percentual":{"type":"integer"},"desconto_maximo_centavos":{"type":"integer"},"pedido_minimo_centavos":{"type":"integer","default":0},"quantidade":{"type":"integer"},"inicio":{"type":"string"},"fim":{"type":"string"},"exibicao":{"type":"string","enum":["loja","codigo"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"id":{"type":"string"}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/promocoes/cupons/{id}/encerrar":{"post":{"summary":"Encerrar agora um cupom em andamento","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"4XX":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"},"encerrar_a_partir_de":{"type":"string"},"erros":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"mensagem":{"type":"string"}}}},"recusados":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"model_id":{"type":"string","nullable":true},"motivo":{"type":"string"}}}}}}}}}}}},"/sales-channels/shopee/importacao/previa":{"get":{"summary":"Pré-visualização de trazer os anúncios da Shopee para a loja","tags":["Canais de Venda - Shopee"],"description":"Os anúncios sem produto da loja em nenhuma variação, com o que cada um traz (fotos, descrição, peso, medidas, GTIN, marca, NCM) e o motivo quando já se sabe que vai ser pulado (apagado, banido, kit, Full, vários armazéns). Mais a sugestão de categoria da loja para cada categoria da Shopee, os depósitos (e quais abastecem a Shopee) e as vagas de produto ativo do plano. Uma chamada de `get_item_base_info` a cada 50 anúncios; o catálogo vem do mesmo cache de 5 minutos da aba Anúncios.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"anuncios":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string"},"foto_url":{"type":"string","nullable":true},"status":{"type":"string"},"url":{"type":"string"},"sku":{"type":"string","nullable":true},"promocao":{"type":"boolean"},"variacoes":{"type":"array","items":{"type":"object","properties":{"model_id":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true},"sku":{"type":"string","nullable":true},"preco_centavos":{"type":"integer","nullable":true},"estoque":{"type":"integer","nullable":true}}}},"preco_min_centavos":{"type":"integer","nullable":true},"preco_max_centavos":{"type":"integer","nullable":true},"estoque_total":{"type":"integer"},"categoria_shopee":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"nome":{"type":"string"},"caminho":{"type":"array","items":{"type":"string"}}}},"traz":{"type":"object","properties":{"fotos":{"type":"integer"},"descricao":{"type":"boolean"},"imagens_na_descricao":{"type":"integer"},"peso_gramas":{"type":"integer","nullable":true},"medidas":{"type":"boolean"},"gtin":{"type":"string","nullable":true},"marca":{"type":"string","nullable":true},"ncm":{"type":"string","nullable":true}}},"pular":{"type":"string","nullable":true}}}},"resumo":{"type":"object","properties":{"anuncios":{"type":"integer"},"a_importar":{"type":"integer"},"pulados":{"type":"integer"},"variacoes":{"type":"integer"},"fotos":{"type":"integer"}}},"categorias":{"type":"array","items":{"type":"object","properties":{"shopee_category_id":{"type":"string"},"nome":{"type":"string"},"caminho":{"type":"array","items":{"type":"string"}},"anuncios":{"type":"integer"},"sugestao":{"type":"object","properties":{"acao":{"type":"string","enum":["existente","criar"]},"categoria_id":{"type":"string"},"nome":{"type":"string"}}}}}},"categorias_da_loja":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"caminho":{"type":"string"}}}},"depositos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"principal":{"type":"boolean"},"abastece_shopee":{"type":"boolean"}}}},"deposito_sugerido":{"type":"string","nullable":true},"depositos_da_shopee":{"type":"string","enum":["escolhidos","padrao","nenhum"]},"vagas_produto_ativo":{"type":"integer","nullable":true},"buffer_seguranca":{"type":"integer"},"importacao_em_andamento":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"status":{"type":"string"},"parada":{"type":"boolean"}}}}}}}}}}},"/sales-channels/shopee/importacoes":{"post":{"summary":"Trazer anúncios da Shopee para a loja (em fila)","tags":["Canais de Venda - Shopee"],"description":"Grava a importação e põe na fila. Cada anúncio vira produto com variações, fotos no armazenamento da loja, descrição, estoque no depósito escolhido e o vínculo por variação com o preço próprio igual ao `original_price` da Shopee: o preço na Shopee não muda e nada é enviado a ela por causa da importação. Uma importação ativa por canal (409).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["item_ids","local_id"],"additionalProperties":false,"properties":{"item_ids":{"type":"array","minItems":1,"maxItems":5000,"items":{"type":"string","minLength":1,"maxLength":40}},"local_id":{"type":"string","minLength":1},"visivel":{"type":"boolean","default":false},"categorias":{"type":"object","additionalProperties":{"type":"object","required":["acao"],"properties":{"acao":{"type":"string","enum":["existente","criar","nenhuma"]},"categoria_id":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true,"maxLength":120}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}}}}},"/sales-channels/shopee/importacoes/{id}/tentar-de-novo":{"post":{"summary":"Tentar de novo só os anúncios que falharam numa importação da Shopee","tags":["Canais de Venda - Shopee"],"description":"Cria uma importação nova com os anúncios que falharam nesta, com as mesmas escolhas (depósito, visível na loja, categorias). O produto que a falha deixou criado é retomado, não duplicado.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}}}}}}}}},"/sales-channels/shopee/importacoes/ultima":{"get":{"summary":"A importação mais recente da Shopee (para a tela retomar o acompanhamento)","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"importacao":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["na_fila","importando","concluida","interrompida"]},"parada":{"type":"boolean"},"total":{"type":"integer"},"processados":{"type":"integer"},"criados":{"type":"integer"},"pulados":{"type":"integer"},"falhas":{"type":"integer"},"erro":{"type":"string","nullable":true},"criada_em":{"type":"string","nullable":true},"iniciada_em":{"type":"string","nullable":true},"concluida_em":{"type":"string","nullable":true},"deposito":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"visivel":{"type":"boolean"},"itens":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string","nullable":true},"situacao":{"type":"string","enum":["pendente","criado","pulado","falhou"]},"motivo":{"type":"string","nullable":true},"aviso":{"type":"string","nullable":true},"produto_id":{"type":"string","nullable":true},"variacoes":{"type":"integer"},"fotos":{"type":"integer"},"fotos_sem_baixar":{"type":"integer"}}}}},"nullable":true}}}}}}}}},"/sales-channels/shopee/importacoes/{id}":{"get":{"summary":"Progresso e resultado de uma importação da Shopee","tags":["Canais de Venda - Shopee"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["na_fila","importando","concluida","interrompida"]},"parada":{"type":"boolean"},"total":{"type":"integer"},"processados":{"type":"integer"},"criados":{"type":"integer"},"pulados":{"type":"integer"},"falhas":{"type":"integer"},"erro":{"type":"string","nullable":true},"criada_em":{"type":"string","nullable":true},"iniciada_em":{"type":"string","nullable":true},"concluida_em":{"type":"string","nullable":true},"deposito":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"nome":{"type":"string"}}},"visivel":{"type":"boolean"},"itens":{"type":"array","items":{"type":"object","properties":{"item_id":{"type":"string"},"nome":{"type":"string","nullable":true},"situacao":{"type":"string","enum":["pendente","criado","pulado","falhou"]},"motivo":{"type":"string","nullable":true},"aviso":{"type":"string","nullable":true},"produto_id":{"type":"string","nullable":true},"variacoes":{"type":"integer"},"fotos":{"type":"integer"},"fotos_sem_baixar":{"type":"integer"}}}}}}}}}}}},"/sales-channels/shopee/importacoes/{id}/retomar":{"post":{"summary":"Retomar uma importação da Shopee interrompida ou parada","tags":["Canais de Venda - Shopee"],"description":"Continua dos anúncios pendentes: o que já entrou não é criado de novo. Recusa (409) enquanto uma execução da importação ainda está viva (a trava no Redis) ou com outra importação ativa no canal.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"Qual loja da Shopee, quando houver mais de uma."},{"schema":{"type":"string","minLength":1},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/tiktok-shop/liberacao":{"get":{"summary":"O TikTok Shop está liberado para este lojista?","tags":["Canais de Venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/tiktok-shop/connect":{"post":{"summary":"Iniciar a autorização da loja TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/tiktok-shop/callback":{"post":{"summary":"Concluir a autorização da loja TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"description":"Recebe code + state, troca pelo par de tokens, lê a loja (Get Authorized Shops), recusa vendedor que não é local do Brasil, grava em sales_channels e inscreve os avisos da loja.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string","minLength":1},"state":{"type":"string","minLength":1}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/status":{"get":{"summary":"Status da conexão com o TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"auth_expire_time":{"type":"string","nullable":true},"autorizacao":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true}}}}}}}}},"/sales-channels/tiktok-shop/health-check":{"post":{"summary":"Testar a conexão com o TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"description":"Resolve o token (renovando se preciso), confere a loja no Get Authorized Shops e os avisos inscritos.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/saude":{"get":{"summary":"Saúde operacional do canal TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/config":{"patch":{"summary":"Ligar ou pausar o TikTok Shop e gravar as regras do canal","tags":["Canais de Venda - TikTok Shop"],"description":"Mesmo contrato do interruptor e da régua de preço dos outros canais (ativo, markup_percentual, buffer_seguranca, margem_liquida_percentual, custo_operacao_centavos), mais os do TikTok: programa_de_frete (o lojista participa do programa de frete, 6% com teto de R$ 50) e armazem_id (o armazém do TikTok que recebe o estoque; null = o padrão da loja). Rodada 5: etiqueta_formato (pdf ou zpl, o padrão da impressão) e cnpj (o CNPJ cadastrado no TikTok, para a pré-checagem da NF-e conferir a raiz). Ativar exige a conexão em ok.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean","nullable":true},"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"programa_de_frete":{"type":"boolean","nullable":true},"armazem_id":{"type":"string","nullable":true,"maxLength":64},"etiqueta_formato":{"type":"string","nullable":true,"enum":["pdf","zpl",null]},"cnpj":{"type":"string","nullable":true,"maxLength":20}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/tiktok-shop/disconnect":{"post":{"summary":"Desconectar a loja TikTok Shop","tags":["Canais de Venda - TikTok Shop"],"description":"Apaga os tokens e a loja da linha (soft-disconnect). Não há revogação por API (estudo §3.2).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"shop_id":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/tiktok-shop/listings":{"get":{"summary":"Anúncios da loja no TikTok Shop, um bloco por produto e uma linha por SKU","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","enum":["todas","vinculados","sugeridos","sem_produto","bloqueados","divergentes"]},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":1000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/listings/vincular":{"post":{"summary":"Vincular SKUs do TikTok Shop a produtos da loja (ou todos os sugeridos por SKU)","tags":["Canais de venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"automatico_por_sku":{"type":"boolean"},"itens":{"type":"array","maxItems":500,"items":{"type":"object","required":["product_id","sku_id","produto_id"],"properties":{"product_id":{"type":"string","minLength":1},"sku_id":{"type":"string","minLength":1},"produto_id":{"type":"string","minLength":1},"variacao_id":{"type":"string","nullable":true}}}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/listings/{listingId}/sync":{"post":{"summary":"Mandar o preço e o estoque deste vínculo agora","tags":["Canais de venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/listings/{listingId}":{"delete":{"summary":"Desfazer o vínculo (o anúncio continua no TikTok Shop)","tags":["Canais de venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/comissao":{"get":{"summary":"A taxa da tabela publicada do TikTok Shop Brasil para um preço","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"integer","minimum":1},"in":"query","name":"preco_centavos","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/armazens":{"get":{"summary":"Os armazéns de venda da loja no TikTok Shop","tags":["Canais de venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/locais":{"get":{"summary":"Depósitos de onde o TikTok Shop publica e reserva","tags":["Canais de venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Definir os depósitos do TikTok Shop (substitui o conjunto)","tags":["Canais de venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/produtos":{"get":{"summary":"Produtos ativos da Varejo Hub para publicar no TikTok Shop, com o preço e o estoque que ele receberia","tags":["Canais de venda - TikTok Shop"],"description":"Mostra os não publicados, os em análise e os reprovados; os que estão no ar (e os vinculados a anúncio que já existia) ficam na aba Anúncios. `situacao` nulo = nunca enviado. `estoque` nulo = o TikTok não tem depósito de onde publicar (aba Regras). `busca` casa nome ou SKU. O filtro dos que estão no ar é feito na página: uma página pode vir com menos itens, e `total` conta todos os produtos ativos da busca.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/preparar/{produtoId}":{"get":{"summary":"Tudo o que o assistente precisa de um produto: categoria sugerida, variações, preço e estoque, armazém, o que falta e a tentativa anterior","tags":["Canais de venda - TikTok Shop"],"description":"`modelos[].preco_centavos` 0 = sem preço (a pendência diz). `loja_pendencias` é o que a loja resolve no Seller Center (Check Listing Prerequisites); `pendencias`, o que falta no cadastro. Atributos, marca e regras da categoria são conferidos no envio.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","minLength":1},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/categorias":{"get":{"summary":"A árvore de categorias do TikTok Shop (v1, 3 níveis), um nível por vez (sem `pai`, a raiz)","tags":["Canais de venda - TikTok Shop"],"description":"`liberada` = a loja pode publicar nela (só `AVAILABLE`); `motivo` diz por que não, em português.","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","maxLength":30},"in":"query","name":"pai","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/categorias/sugestao":{"get":{"summary":"A categoria que o TikTok sugere pelo nome do produto (só a folha liberada para a loja), com o caminho","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"query","name":"nome","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/categorias/{id}/atributos":{"get":{"summary":"Os atributos de produto da categoria (obrigatórios, condicionais, tipo e valores); os de venda vêm das variações","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","pattern":"^[0-9]{1,30}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/categorias/{id}/marcas":{"get":{"summary":"As marcas que a loja pode usar na categoria (autorizadas, ou não autorizadas fora da lista T1)","tags":["Canais de venda - TikTok Shop"],"description":"`obrigatoria` é sempre falso nesta rodada: a regra da categoria não diz ([NV] no BR); sem marca = \"Sem marca\".","parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","maxLength":100},"in":"query","name":"busca","required":false},{"schema":{"type":"string","pattern":"^[0-9]{1,30}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/categorias/{id}/regras":{"get":{"summary":"As regras da categoria: tetos, dimensões obrigatórias, certificados e tabela de medidas","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","pattern":"^[0-9]{1,30}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub no TikTok Shop (idempotente por produto e loja)","tags":["Canais de venda - TikTok Shop"],"description":"Confere a loja e o produto (Check Listing Prerequisites e Check Product Listing), sobe as fotos e cria o produto com todos os SKUs (chave de idempotência), gravando uma linha de vínculo por SKU. O produto nasce em análise; o veredito chega pelo aviso (37 e 5) ou pela situação. O segundo clique devolve o que está em andamento ou pronto, sem criar outro produto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["produto_id","categoria_id","marca_id","atributos"],"properties":{"produto_id":{"type":"string","minLength":1},"categoria_id":{"type":"string","pattern":"^[0-9]{1,30}$"},"marca_id":{"type":"string","nullable":true,"pattern":"^[0-9]{1,30}$"},"atributos":{"type":"array","maxItems":200,"items":{"type":"object","additionalProperties":false,"required":["id","valor_ids"],"properties":{"id":{"type":"string","pattern":"^[0-9]{1,30}$"},"valor_ids":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[0-9]{1,30}$"}},"valor_texto":{"type":"string","maxLength":2000}}}},"titulo":{"type":"string","maxLength":300},"descricao":{"type":"string","maxLength":20000}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicar/{productId}/reenviar":{"post":{"summary":"Corrigir e reenviar um produto reprovado (ou em análise): Edit Product com TODOS os SKUs e seus ids","tags":["Canais de venda - TikTok Shop"],"description":"SKU que não vai no Edit é SKU apagado no TikTok: se algum SKU do produto não tiver variação ativa na Varejo Hub, o reenvio é recusado sem chamar o TikTok. 404 = o produto não foi publicado por esta loja.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["produto_id","categoria_id","marca_id","atributos"],"properties":{"produto_id":{"type":"string","minLength":1},"categoria_id":{"type":"string","pattern":"^[0-9]{1,30}$"},"marca_id":{"type":"string","nullable":true,"pattern":"^[0-9]{1,30}$"},"atributos":{"type":"array","maxItems":200,"items":{"type":"object","additionalProperties":false,"required":["id","valor_ids"],"properties":{"id":{"type":"string","pattern":"^[0-9]{1,30}$"},"valor_ids":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[0-9]{1,30}$"}},"valor_texto":{"type":"string","maxLength":2000}}}},"titulo":{"type":"string","maxLength":300},"descricao":{"type":"string","maxLength":20000}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","pattern":"^[0-9]{1,30}$"},"in":"path","name":"productId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/publicacao/situacao/{productId}":{"get":{"summary":"A situação do produto no TikTok agora (Get Product: status, auditoria e motivos), gravada nas linhas","tags":["Canais de venda - TikTok Shop"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"shop_id","required":false,"description":"A loja do TikTok Shop (a conectada; outra é 404)."},{"schema":{"type":"string","pattern":"^[0-9]{1,30}$"},"in":"path","name":"productId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/despacho":{"get":{"summary":"Despacho do pedido do TikTok Shop: janela, prazo, NF-e, pacotes, etiqueta e rastreio","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/nota-fiscal":{"post":{"summary":"Envia a NF-e do pacote ao TikTok (XML anexado ou a nota do pedido), com pré-checagem; o resultado chega pelo webhook 36","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"in":"query","name":"package_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/envio/opcoes":{"get":{"summary":"Coleta, postagem ou envio próprio do pacote: os horários do TikTok (com o recomendado) e as transportadoras","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"in":"query","name":"package_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/envio":{"post":{"summary":"Despacha o pacote no TikTok (Ship Package): coleta, postagem ou envio próprio com rastreio","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["package_id","modo"],"properties":{"package_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"modo":{"type":"string","enum":["coleta","postagem","proprio"]},"horario_id":{"type":"string","maxLength":32},"transportadora_id":{"type":"string","maxLength":64},"rastreio":{"type":"string","maxLength":64}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/rastreio":{"patch":{"summary":"Corrige o rastreio do envio próprio (Update Package Shipping Info), até 72 h depois do envio","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["package_id","transportadora_id","rastreio"],"properties":{"package_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"transportadora_id":{"type":"string","maxLength":64},"rastreio":{"type":"string","maxLength":64}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/etiqueta":{"post":{"summary":"Pede a etiqueta do TikTok do pacote (PDF ou ZPL, com ou sem a DANFE simplificada) e devolve o link assinado","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["package_id"],"properties":{"package_id":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"formato":{"type":"string","enum":["pdf","zpl"]},"com_danfe":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"Situação da etiqueta do pacote e o link assinado quando pronta","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"in":"query","name":"package_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/notas-em-lote":{"post":{"summary":"Envia ao TikTok as NF-e do ERP de vários pedidos (Upload Invoice numa chamada)","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/envio-em-lote":{"post":{"summary":"Despacha vários pedidos (Batch Ship Packages), coleta ou postagem","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids","modo"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"modo":{"type":"string","enum":["coleta","postagem"]},"horario_id":{"type":"string","maxLength":32}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/etiquetas-em-lote":{"post":{"summary":"Etiquetas de vários pedidos num arquivo só (uma: PDF ou ZPL; várias: ZIP). Idempotente: repita enquanto vier gerando","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"formato":{"type":"string","enum":["pdf","zpl"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/cancelamento":{"get":{"summary":"Cancelamento do pedido do TikTok Shop: o pedido do comprador a responder (48 h), se a loja pode cancelar e os motivos","tags":["Canais de Venda - TikTok Shop"],"description":"Lê na hora o Search Cancellations, o Get Aftersale Eligibility e o Get Decision Eligibility. Leitura que falha vira aviso em `erros`.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Aceita ou recusa o cancelamento pedido pelo comprador (Approve ou Reject Cancellation); o pedido só cancela quando o TikTok confirma","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["decisao"],"additionalProperties":false,"properties":{"decisao":{"type":"string","enum":["aceitar","recusar"]},"motivo_id":{"type":"string","minLength":1,"maxLength":200},"texto":{"type":"string","maxLength":500}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/pedidos/{pedidoId}/cancelar":{"post":{"summary":"Cancela o pedido pela loja (Cancel Order) com o motivo da elegibilidade; conta contra a loja no TikTok","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo_id"],"additionalProperties":false,"properties":{"motivo_id":{"type":"string","minLength":1,"maxLength":200}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/cancelamentos-a-responder":{"get":{"summary":"Os pedidos do TikTok com cancelamento do comprador esperando a resposta da loja (o filtro da aba Pedidos)","tags":["Canais de Venda - TikTok Shop"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/devolucoes/{devolucaoId}":{"get":{"summary":"Devolução do TikTok Shop: tipo, motivo, valor, prazo, próxima ação, provas do comprador, ações e motivos de recusa","tags":["Canais de Venda - TikTok Shop"],"description":"Lê na hora o Search Returns, o Get Decision Eligibility e o Get Return Records (sem cache: prazo e estado mudam).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/devolucoes/{devolucaoId}/aceitar":{"post":{"summary":"Aceita o reembolso ou a devolução (Approve Return: APPROVE_REFUND ou APPROVE_RETURN)","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/devolucoes/{devolucaoId}/recusar":{"post":{"summary":"Recusa o reembolso ou a devolução com o motivo do TikTok (Reject Return: REJECT_REFUND ou REJECT_RETURN)","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo_id"],"additionalProperties":false,"properties":{"motivo_id":{"type":"string","minLength":1,"maxLength":200},"texto":{"type":"string","maxLength":500}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/devolucoes/{devolucaoId}/confirmar-recebimento":{"post":{"summary":"Confirma que o pacote devolvido chegou (APPROVE_RECEIVED_PACKAGE); o estoque volta pelo recebimento de canal","tags":["Canais de Venda - TikTok Shop"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/tiktok-shop/devolucoes/{devolucaoId}/recusar-recebimento":{"post":{"summary":"Recusa o pacote devolvido com o motivo do TikTok (REJECT_RECEIVED_PACKAGE); o estoque não volta","tags":["Canais de Venda - TikTok Shop"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo_id"],"additionalProperties":false,"properties":{"motivo_id":{"type":"string","minLength":1,"maxLength":200},"texto":{"type":"string","maxLength":500}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/listings":{"get":{"summary":"Anúncios da conta na Amazon, uma linha por SKU","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"string","enum":["todas","vinculados","sugeridos","sem_produto","bloqueados","divergentes","a_venda","so_visivel","com_problema","em_analise"]},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":1000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/listings/vincular":{"post":{"summary":"Vincular SKUs da Amazon a variações da loja (ou todos os sugeridos por SKU)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"automatico_por_sku":{"type":"boolean"},"itens":{"type":"array","maxItems":500,"items":{"type":"object","required":["produto_id"],"properties":{"sku":{"type":"string","minLength":1},"product_id":{"type":"string","minLength":1},"asin":{"type":"string","nullable":true},"sku_id":{"type":"string","nullable":true},"produto_id":{"type":"string","minLength":1},"variacao_id":{"type":"string","nullable":true}}}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/listings/{listingId}/sync":{"post":{"summary":"Mandar o preço e o estoque deste vínculo agora","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/listings/{listingId}":{"delete":{"summary":"Desfazer o vínculo (o anúncio continua na Amazon)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/importacao":{"post":{"summary":"Pedir à Amazon o relatório de todos os anúncios (a prévia sai em alguns minutos)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O estado do relatório de anúncios e a prévia (casados, sem par, ambíguos)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/importacao/confirmar":{"post":{"summary":"Criar os vínculos dos SKUs casados da prévia (todos, ou só os informados)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"skus":{"type":"array","maxItems":5000,"items":{"type":"string","minLength":1}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/comissao":{"get":{"summary":"A comissão da tabela da Amazon Brasil para um preço (centavos) e categoria","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"integer","minimum":1},"in":"query","name":"preco","required":false},{"schema":{"type":"integer","minimum":1},"in":"query","name":"preco_centavos","required":false},{"schema":{"type":"string","maxLength":64},"in":"query","name":"categoria","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/categorias-comissao":{"get":{"summary":"As categorias da tabela de comissão da Amazon Brasil","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/locais":{"get":{"summary":"Depósitos de onde a Amazon publica e reserva","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Definir os depósitos da Amazon (substitui o conjunto)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/produtos":{"get":{"summary":"Produtos ativos da Varejo Hub para publicar na Amazon, com a situação da publicação","tags":["Canais de Venda - Amazon"],"description":"`situacao`: `falta_sku` e `falta_ean` (alguma variação sem SKU ou sem EAN), `precisa_respostas` (a última prévia achou obrigatório sem resposta), `pronto` (nada conhecido impede; a prévia confere com a Amazon), e depois do envio `em_analise`, `a_venda`, `recusado` ou `parcial` (mistura, ou parte ainda não enviada). Sem chamada à Amazon. `busca` casa nome ou SKU.","parameters":[{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":1000,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/preparar/{produtoId}":{"get":{"summary":"A prévia por variação: oferta num produto da Amazon, produto novo ou bloqueado; o tipo sugerido, o tema e o formulário","tags":["Canais de Venda - Amazon"],"description":"Procura o EAN de cada variação no catálogo da Amazon (oferta: título, foto e ASIN de lá; vários: `candidatos` para escolher), confere a restrição do ASIN (`restricao` com o link de aprovação), sugere o tipo de produto pelo título e monta o formulário dos obrigatórios do schema (com `valor_sugerido` do que o Hub já sabe e `valor_respondido` das respostas salvas). Família (cor e tamanho) vem em `tema_variacao`, com o SKU pai. Produto sem variações vem com uma variação de `variacao_id` nulo (a chave de `escolhas` é `produto`).","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/tipos":{"get":{"summary":"Tipos de produto da Amazon pela busca (para trocar o sugerido)","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"string","maxLength":100},"in":"query","name":"busca","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/{produtoId}/respostas":{"put":{"summary":"Salvar o tipo de produto, as respostas do formulário e a escolha de ASIN no caso ambíguo","tags":["Canais de Venda - Amazon"],"description":"`respostas` substitui as anteriores (valor: texto, número, sim ou não, ou `{ valor, unidade }`). `escolhas` soma às anteriores: `{ <variacao_id ou \"produto\">: <ASIN> }`. Fica na ficha do produto no canal, sem migration.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["tipo","respostas"],"properties":{"tipo":{"type":"string","pattern":"^[A-Z0-9_]{1,80}$"},"respostas":{"type":"object","maxProperties":200,"propertyNames":{"pattern":"^[a-z0-9_]{1,100}$"}},"escolhas":{"type":"object","maxProperties":300,"additionalProperties":{"type":"string","pattern":"^[A-Z0-9]{8,20}$"}}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/{produtoId}/validar":{"post":{"summary":"Conferir com a Amazon (VALIDATION_PREVIEW) cada SKU que iria, sem gravar nada","tags":["Canais de Venda - Amazon"],"description":"`por_variacao[].status`: `VALID`, `INVALID` (com as `issues` em português), `ERRO` (a Amazon não respondeu) ou `BLOQUEADO` (sem SKU, sem EAN, restrito, ambíguo sem escolha). Na família, o SKU pai vem primeiro.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub na Amazon (o pai primeiro na família; repetível)","tags":["Canais de Venda - Amazon"],"description":"Cada SKU passa pela conferência (VALIDATION_PREVIEW) e só o válido é enviado. `ACCEPTED` fica em análise e ganha o vínculo (uma linha por SKU, como na aba Anúncios); o veredito chega pelo aviso da Amazon ou pela releitura. O SKU já em análise ou à venda não é reenviado; o recusado é (o envio por SKU substitui, não duplica).","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["produto_id"],"properties":{"produto_id":{"type":"string","minLength":1,"maxLength":64}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/publicacao/situacao/{produtoId}":{"get":{"summary":"A situação de cada SKU enviado (em análise, à venda, recusado com o motivo, enviando)","tags":["Canais de Venda - Amazon"],"description":"O SKU em análise há mais de um minuto sem conferência é relido na Amazon (getListingsItem) antes de responder. Na família, o SKU pai vem com `papel: \"pai\"`. Produto nunca enviado: `variacoes` vazio.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/despacho":{"get":{"summary":"Despacho do pedido da Amazon: quem envia, NF-e, agendamento (DBA), envio próprio, prazo e o que a loja pode fazer","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/nota-fiscal":{"post":{"summary":"Envia a NF-e à Amazon (XML anexado ou a nota do ERP), com pré-checagem; a Amazon responde em cerca de 5 minutos","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/horarios":{"get":{"summary":"Os horários de coleta do Easy Ship (DBA). Medidas e peso opcionais; sem elas, as do cadastro dos produtos","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"number","exclusiveMinimum":0,"maximum":100000},"in":"query","name":"comprimento_cm","required":false},{"schema":{"type":"number","exclusiveMinimum":0,"maximum":100000},"in":"query","name":"largura_cm","required":false},{"schema":{"type":"number","exclusiveMinimum":0,"maximum":100000},"in":"query","name":"altura_cm","required":false},{"schema":{"type":"number","exclusiveMinimum":0,"maximum":100000},"in":"query","name":"peso_g","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/agendar":{"post":{"summary":"Agenda a coleta do DBA no horário escolhido e guarda a etiqueta (o link da Amazon vence em 3 minutos)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["slot_id"],"properties":{"slot_id":{"type":"string","minLength":1,"maxLength":200},"formato":{"type":"string","enum":["PDF","ZPL","pdf","zpl"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/etiqueta":{"get":{"summary":"A etiqueta guardada (PDF ou ZPL) com o link assinado; a que falta é recuperada na Amazon","tags":["Canais de Venda - Amazon"],"parameters":[{"schema":{"type":"string","enum":["PDF","ZPL","pdf","zpl"]},"in":"query","name":"formato","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/confirmar-envio":{"post":{"summary":"Confirma o envio próprio na Amazon (confirmShipment): transportadora e rastreio (só o código, sem link)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["transportadora","rastreio"],"properties":{"transportadora":{"type":"string","minLength":1,"maxLength":64},"nome_transportadora":{"type":"string","maxLength":100,"nullable":true},"servico":{"type":"string","maxLength":100,"nullable":true},"rastreio":{"type":"string","maxLength":300},"data":{"type":"string","maxLength":40,"nullable":true}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/transportadoras":{"get":{"summary":"As transportadoras do envio próprio com o código que a Amazon aceita (\"Outra\" pede o nome)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/notas-em-lote":{"post":{"summary":"Envia à Amazon as NF-e do ERP de vários pedidos","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/agendar-em-lote":{"post":{"summary":"Agenda a coleta de vários pedidos DBA (25 por chamada à Amazon) e guarda as etiquetas","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"slot_padrao":{"type":"string","maxLength":200,"nullable":true},"formato":{"type":"string","enum":["PDF","ZPL","pdf","zpl"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/etiquetas-em-lote":{"post":{"summary":"Etiquetas de vários pedidos num arquivo só (uma: PDF ou ZPL; várias: ZIP)","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"formato":{"type":"string","enum":["PDF","ZPL","pdf","zpl"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/cancelamento":{"get":{"summary":"Cancelamento do pedido da Amazon: o pedido do comprador, a situação do feed de cancelamento e os motivos","tags":["Canais de Venda - Amazon"],"description":"Lê o que está gravado (o aviso da Amazon e o feed conferido pelo cron); não chama a Amazon.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Responde ao pedido de cancelamento do comprador: cancelar (feed POST_ORDER_ACKNOWLEDGEMENT_DATA, BuyerCanceled) ou despachar mesmo assim","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["decisao"],"additionalProperties":false,"properties":{"decisao":{"type":"string","enum":["cancelar","despachar"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/pedidos/{pedidoId}/cancelar":{"post":{"summary":"Cancela o pedido pela loja (feed POST_ORDER_ACKNOWLEDGEMENT_DATA com o motivo); conta na taxa de cancelamento da conta","tags":["Canais de Venda - Amazon"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo_id"],"additionalProperties":false,"properties":{"motivo_id":{"type":"string","minLength":1,"maxLength":60}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/cancelamentos-a-responder":{"get":{"summary":"Os pedidos da Amazon com cancelamento pedido pelo comprador esperando a resposta da loja (o filtro da aba Pedidos)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/devolucoes/{devolucaoId}":{"get":{"summary":"Devolução da Amazon: RMA, motivo, situação, valor reembolsado e se o pacote voltou (do relatório diário de devoluções)","tags":["Canais de Venda - Amazon"],"description":"Autorizar, recusar e reembolsar é no Seller Central (a API da Amazon não tem essas ações).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/liberacao":{"get":{"summary":"A Amazon está liberada para este lojista?","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/amazon/connect":{"post":{"summary":"Iniciar a autorização da conta Amazon (consentimento no Seller Central)","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/amazon/entrar":{"post":{"summary":"Log-in URI da Amazon: devolver o lojista ao Seller Central","tags":["Canais de Venda - Amazon"],"description":"A Amazon traz o lojista com amazon_callback_uri, amazon_state e selling_partner_id. Gera um state novo do tenant e devolve o endereço de volta (só dentro de /apps/authorize/confirm/ do Seller Central).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["amazon_callback_uri","amazon_state"],"properties":{"amazon_callback_uri":{"type":"string","minLength":1,"maxLength":2000},"amazon_state":{"type":"string","minLength":1,"maxLength":2000},"selling_partner_id":{"type":"string","nullable":true,"maxLength":64},"version":{"type":"string","nullable":true,"maxLength":16}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirect_url":{"type":"string"}}}}}}}}},"/sales-channels/amazon/callback":{"post":{"summary":"Concluir a autorização da conta Amazon","tags":["Canais de Venda - Amazon"],"description":"Recebe o spapi_oauth_code (como code), o state e o selling_partner_id; troca o código, lê as participações, recusa conta sem a Amazon.com.br, grava em sales_channels e assina os avisos da conta.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state","selling_partner_id"],"properties":{"code":{"type":"string","minLength":1},"state":{"type":"string","minLength":1},"selling_partner_id":{"type":"string","minLength":1,"maxLength":64}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/status":{"get":{"summary":"Status da conexão com a Amazon","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"auth_expire_time":{"type":"string","nullable":true},"autorizacao":{"type":"object","additionalProperties":true,"nullable":true},"conta":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true}}}}}}}}},"/sales-channels/amazon/health-check":{"post":{"summary":"Testar a conexão com a Amazon","tags":["Canais de Venda - Amazon"],"description":"Resolve o token (renovando uma vez se a Amazon recusar), confere as participações e as assinaturas de aviso (reinscreve as que faltarem).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/saude":{"get":{"summary":"Saúde operacional do canal Amazon","tags":["Canais de Venda - Amazon"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/amazon/config":{"patch":{"summary":"Ligar ou pausar a Amazon e gravar as regras do canal","tags":["Canais de Venda - Amazon"],"description":"O interruptor (ativo; ativar exige a conexão em ok) e, desde a Rodada 3, a régua de preço da casa (markup_percentual, margem_liquida_percentual, custo_operacao_centavos, buffer_seguranca) e as chaves da Amazon: prazo_manuseio_dias (1 a 30; vai a todos os anúncios vinculados; null apaga) e categoria_comissao (id de /categorias-comissao; null volta ao padrão). Régua ou categoria reenviam o preço dos vínculos; buffer, o estoque.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean","nullable":true},"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"prazo_manuseio_dias":{"type":"integer","minimum":1,"maximum":30,"nullable":true},"categoria_comissao":{"type":"string","nullable":true,"maxLength":64}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"prazo":{"type":"object","nullable":true,"properties":{"enviados":{"type":"integer"},"em_segundo_plano":{"type":"boolean"},"recusados":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"motivo":{"type":"string"}}}}}}}}}}}}}},"/sales-channels/amazon/disconnect":{"post":{"summary":"Desconectar a conta Amazon","tags":["Canais de Venda - Amazon"],"description":"Remove as assinaturas de aviso (sem lojista, best effort), apaga os tokens e a conta da linha (soft-disconnect).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"selling_partner_id":{"type":"string","nullable":true},"assinaturas_removidas":{"type":"integer"},"assinaturas_com_falha":{"type":"integer"}}}}}}}}},"/sales-channels/temu/liberacao":{"get":{"summary":"A Temu está liberada para este lojista?","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/temu/connect":{"post":{"summary":"Iniciar a autorização da loja Temu (Seller Center)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/temu/callback":{"post":{"summary":"Concluir a autorização da loja Temu (retorno do Seller Center)","tags":["Canais de Venda - Temu"],"description":"Recebe code, state e, quando a Temu manda, callback_host e app_key; confere o gateway, troca o código, relê a autorização, recusa loja que não é local da Temu Brasil, grava em sales_channels e inscreve os avisos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string","minLength":1,"maxLength":512},"state":{"type":"string","minLength":1,"maxLength":2000},"callback_host":{"type":"string","nullable":true,"maxLength":255},"app_key":{"type":"string","nullable":true,"maxLength":255}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string"},"external_user_id":{"type":"string"},"region":{"type":"string"},"avisos":{"type":"string"},"permissoes_faltando":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"impede":{"type":"string"}}}}}}}}}}}},"/sales-channels/temu/token":{"post":{"summary":"Conectar a loja Temu com o token copiado do Seller Center","tags":["Canais de Venda - Temu"],"description":"O lojista autoriza o app em Seller Center > Gerenciamento de sistema > Gerenciamento de autorização e cola o token. Relê a autorização no gateway global; o resto é igual ao callback.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["access_token"],"properties":{"access_token":{"type":"string","maxLength":4000}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string"},"external_user_id":{"type":"string"},"region":{"type":"string"},"avisos":{"type":"string"},"permissoes_faltando":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"impede":{"type":"string"}}}}}}}}}}}},"/sales-channels/temu/status":{"get":{"summary":"Status da conexão com a Temu","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"auth_expire_time":{"type":"string","nullable":true},"autorizacao":{"type":"object","additionalProperties":true,"nullable":true},"permissoes":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true}}}}}}}}},"/sales-channels/temu/health-check":{"post":{"summary":"Testar a conexão com a Temu","tags":["Canais de Venda - Temu"],"description":"Relê a autorização (bg.open.accesstoken.info.get): loja, escopos, vencimento e avisos; reinscreve os avisos que faltarem.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/saude":{"get":{"summary":"Saúde operacional do canal Temu","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/config":{"patch":{"summary":"Ligar ou pausar a Temu e gravar a régua de preço","tags":["Canais de Venda - Temu"],"description":"O interruptor (ativo; ativar exige a conexão em ok) e, desde a Rodada 3, a régua de preço da casa (markup_percentual, margem_liquida_percentual, custo_operacao_centavos, buffer_seguranca). A régua calcula o preço base (o que o lojista recebe); a Temu não informa comissão. Régua reenvia o preço dos vínculos; buffer, o estoque.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean","nullable":true},"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"armazem_envio":{"type":"string","minLength":1,"maxLength":64,"nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/temu/disconnect":{"post":{"summary":"Desconectar a loja Temu","tags":["Canais de Venda - Temu"],"description":"Cancela os avisos da loja (melhor esforço), apaga o token e a loja da linha (soft-disconnect).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"mall_id":{"type":"string","nullable":true},"avisos_cancelados":{"type":"boolean"}}}}}}}}},"/sales-channels/temu/listings":{"get":{"summary":"Anúncios da loja na Temu, uma linha por SKU (página pelo token da Temu)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","enum":["todas","vinculados","sugeridos","sem_produto","divergentes","a_venda","inativo","incompleto","rascunho","excluido"]},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"string","maxLength":2000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/listings/vincular":{"post":{"summary":"Vincular um SKU da Temu a uma variação da loja (ou todos os sugeridos pelo código)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sugeridos":{"type":"boolean"},"goods_id":{"type":"string","pattern":"^[0-9]{1,24}$"},"sku_id":{"type":"string","pattern":"^[0-9]{1,24}$"},"produto_id":{"type":"string","nullable":true},"variacao_id":{"type":"string","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/listings/{listingId}/sync":{"post":{"summary":"Mandar o estoque (e o preço base, com a liberação) deste vínculo agora","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/listings/{listingId}":{"delete":{"summary":"Desfazer o vínculo (o anúncio e o código continuam na Temu)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/listings/{listingId}/preco":{"get":{"summary":"O preço base esperado e a situação do price order na Temu","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/importacao":{"post":{"summary":"Pedir a leitura do catálogo inteiro da Temu (a prévia sai em alguns minutos)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O estado da leitura do catálogo e a prévia (casados, sem par, ambíguos, sem código)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/importacao/confirmar":{"post":{"summary":"Criar os vínculos dos SKUs casados da prévia (todos, ou só os informados)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"skus":{"type":"array","maxItems":5000,"items":{"type":"string","minLength":1}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/locais":{"get":{"summary":"Depósitos que abastecem a Temu (a soma deles vai a cada SKU)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Definir os depósitos da Temu (substitui o conjunto)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/modelos-de-frete":{"get":{"summary":"Os modelos de frete da loja na Temu (obrigatório em todo produto do Brasil); vazio = passo guiado","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/produtos":{"get":{"summary":"Produtos ativos da Varejo Hub para publicar na Temu, com a situação de cada um","tags":["Canais de Venda - Temu"],"description":"A situação sai do envio (avaliação de preço, em análise, à venda...) ou do diagnóstico local (falta modelo de frete, peso ou medidas, fotos, variações, respostas). Os vinculados a anúncio que já existia (aba Anúncios) ficam fora; uma página pode vir com menos itens, e `total` conta todos os produtos ativos da busca.","parameters":[{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/preparar/{produtoId}":{"get":{"summary":"Tudo o que a tela de publicar precisa de um produto: categoria sugerida, frete, marca, variações, SKUs, fotos, formulário e bloqueios","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/categorias":{"get":{"summary":"A árvore de categorias da Temu, um nível por vez (`pai` 0 ou vazio = raiz); só as disponíveis","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","maxLength":24},"in":"query","name":"pai","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/categorias/sugestao":{"get":{"summary":"A categoria que a Temu sugere pelo título (a primeira é a recomendada), com o caminho quando conhecido","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":500},"in":"query","name":"titulo","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/categorias/{id}/atributos":{"get":{"summary":"Os atributos da categoria em português, como campos da tela (com o modelo de frete, os transnacionais)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","maxLength":100},"in":"query","name":"modelo_frete","required":false},{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/categorias/{id}/variacoes":{"get":{"summary":"Os tipos de variação da categoria (`tipo_valor` 0 só a lista, 1 valor livre, 2 os dois)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/categorias/{id}/regras":{"get":{"summary":"As regras da categoria (campo obrigatório, opcional ou desabilitado) e se é vestuário","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/{produtoId}/respostas":{"put":{"summary":"Gravar as respostas do lojista (categoria, frete, prazo, marca, código fiscal, atributos, juntar variações)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["atributos"],"properties":{"categoria_id":{"type":"string","nullable":true,"pattern":"^[0-9]{1,24}$"},"modelo_frete_id":{"type":"string","nullable":true,"maxLength":100},"prazo_despacho":{"type":"integer","enum":[1,2]},"marca":{"type":"object","properties":{"trademark_id":{"type":"string","pattern":"^[0-9]{1,24}$"},"sem_marca":{"type":"boolean"}}},"codigo_fiscal":{"type":"string","maxLength":60},"atributos":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"vid":{"type":"string","maxLength":30},"valor":{"type":"string","maxLength":2000},"numero":{"type":"string","maxLength":50},"unidade":{"type":"string","maxLength":30}}}},"achatar":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/{produtoId}/conferir":{"post":{"summary":"Conferir antes de enviar: checagens locais, palavras proibidas e códigos na Temu (nada é criado)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub na Temu (o mesmo código não vira outro produto)","tags":["Canais de Venda - Temu"],"description":"Checagens locais, palavras proibidas, códigos, fotos (reenviadas à Temu logo antes) e `temu.local.goods.v2.add`. O vínculo (uma linha por SKU) nasce na resposta. Limite diário da Temu: o envio fica na fila para amanhã.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","minLength":1,"maxLength":64}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicar/{produtoId}/reenviar":{"post":{"summary":"Reenviar depois de corrigir um erro (ou da fila do limite diário); produto já criado devolve a situação","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/publicacao/situacao/{produtoId}":{"get":{"summary":"A situação do produto na Temu (relida do `publish.status` enquanto a Temu decide)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/despacho":{"get":{"summary":"Despacho do pedido da Temu: modo, NF-e, pacote, cotação, pacotes, envio próprio, prazo, bloqueio e o que a loja pode fazer","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/armazens":{"get":{"summary":"Os armazéns da loja na Temu que compram etiqueta dela","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/cotacao":{"post":{"summary":"Cota o frete na Temu com a chave da NF-e (o pacote e o armazém vêm do cadastro e das Regras, ou do corpo)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"armazem_id":{"type":"string","maxLength":64,"nullable":true},"pacote":{"type":"object","nullable":true,"required":["peso_kg","comprimento_cm","largura_cm","altura_cm"],"properties":{"peso_kg":{"type":"number","exclusiveMinimum":0,"maximum":100000},"comprimento_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"largura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"altura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/etiqueta":{"post":{"summary":"Compra a etiqueta da Temu (cota de novo se a cotação passou de 30 min); o resultado chega pela releitura","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"armazem_id":{"type":"string","maxLength":64,"nullable":true},"pacote":{"type":"object","nullable":true,"required":["peso_kg","comprimento_cm","largura_cm","altura_cm"],"properties":{"peso_kg":{"type":"number","exclusiveMinimum":0,"maximum":100000},"comprimento_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"largura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"altura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O PDF guardado da etiqueta (baixado de novo na Temu quando falta)","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"query","name":"pacote","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/etiqueta/tentar-de-novo":{"post":{"summary":"Compra de novo a etiqueta que falhou (shipment.update, sem SUCCESSFUL_RETRY)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pacote_sn"],"properties":{"pacote_sn":{"type":"string","minLength":1,"maxLength":64},"pacote":{"type":"object","nullable":true,"required":["peso_kg","comprimento_cm","largura_cm","altura_cm"],"properties":{"peso_kg":{"type":"number","exclusiveMinimum":0,"maximum":100000},"comprimento_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"largura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000},"altura_cm":{"type":"number","exclusiveMinimum":0,"maximum":100000}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/etiqueta/trocar-nota":{"post":{"summary":"Manda à Temu a chave da NF-e emitida mais recente do pedido para a etiqueta pronta (SUCCESSFUL_RETRY)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pacote_sn"],"properties":{"pacote_sn":{"type":"string","minLength":1,"maxLength":64}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/coleta/horarios":{"get":{"summary":"Os horários de coleta que a Temu oferece (segundos); sem horário, a frase da coleta combinada","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/coleta":{"post":{"summary":"Reserva a coleta no horário escolhido (o par da lista de horários)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["inicio","fim"],"properties":{"inicio":{"anyOf":[{"type":"integer","minimum":1},{"type":"string","minLength":1,"maxLength":40}]},"fim":{"anyOf":[{"type":"integer","minimum":1},{"type":"string","minLength":1,"maxLength":40}]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Cancela a coleta reservada","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/confirmar-envio":{"post":{"summary":"Adianta o \"enviado\" na Temu (shipped.package.confirm) para a etiqueta pronta","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/transportadoras":{"get":{"summary":"As transportadoras da Temu no Brasil (envio próprio liberado)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/envio-proprio":{"post":{"summary":"Confirma o envio próprio (só pedido liberado pela Temu): transportadora da lista e rastreio","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["transportadora_id","rastreio"],"properties":{"transportadora_id":{"type":"string","minLength":1,"maxLength":40},"rastreio":{"type":"string","maxLength":300}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/etiquetas-em-lote":{"post":{"summary":"Compra a etiqueta de vários pedidos, um por vez (os sem NF-e autorizada saem com o motivo)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/etiquetas-em-lote/arquivo":{"post":{"summary":"Um ZIP com as etiquetas guardadas dos pedidos (link assinado de 10 min) e os recusados com o motivo","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/cancelamento":{"get":{"summary":"Cancelamento do pedido da Temu: os pedidos do comprador (prazo de 24 h), o cancelamento por falta de estoque e os itens cancelados no pacote","tags":["Canais de Venda - Temu"],"description":"Relê a Temu quando há pedido do comprador aberto ou o rótulo pending_buyer_cancellation sem registro.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Responde ao pedido de cancelamento do comprador: aceitar (bg.aftersales.cancel.agree) ou recusar despachando (compra da etiqueta com DENY_CANCELLATION)","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["parent_after_sales_sn","decisao"],"properties":{"parent_after_sales_sn":{"type":"string","minLength":1,"maxLength":64},"decisao":{"type":"string","enum":["aceitar","despachar"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/pedidos/{pedidoId}/cancelar-por-falta-de-estoque":{"post":{"summary":"Pede à Temu o cancelamento por falta de estoque (temu.order.cancel.outofstock.apply) dos itens escolhidos (sem a lista, todos); a Temu analisa","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"order_sns":{"type":"array","items":{"type":"string","minLength":1,"maxLength":64},"maxItems":100,"nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/cancelamentos-a-responder":{"get":{"summary":"Os pedidos da Temu com cancelamento pedido pelo comprador esperando a resposta da loja (o filtro da aba Pedidos)","tags":["Canais de Venda - Temu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}":{"get":{"summary":"Devolução da Temu: tipo, situação e motivo em português, itens, valores, logística de volta e as ações que a Temu oferece agora","tags":["Canais de Venda - Temu"],"description":"Recusar a devolução, reembolsar parte e contestar ficam no Seller Center (a API da Temu não tem essas ações).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}/reembolsar":{"post":{"summary":"Reembolsa o valor TOTAL da devolução (temu.aftersales.refund.issue); valor diferente do confirmado devolve 409 com o valor atual","tags":["Canais de Venda - Temu"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["confirmar_valor_centavos"],"properties":{"confirmar_valor_centavos":{"type":"integer","minimum":0}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}/etiqueta/preparar":{"get":{"summary":"O que a etiqueta de devolução precisa: entrega (ponto ou coleta), armazéns, transportadoras, janelas do comprador e prazos","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}/etiqueta/endereco-do-comprador":{"get":{"summary":"O endereço do comprador para a etiqueta de devolução, lido na Temu no clique; não é gravado","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}/etiqueta":{"post":{"summary":"Envia a etiqueta de devolução à Temu (multipart: armazem_id, transportadora_id, rastreio, arquivo?, modo_coleta?, inicio?, fim?, ate? em ms); o arquivo fica no bucket","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O arquivo guardado da etiqueta de devolução","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/temu/devolucoes/{devolucaoId}/confirmar-recebimento":{"post":{"summary":"Confirma o pacote recebido quando a Temu reembolsou sem informar a chegada à loja; o estoque volta uma vez","tags":["Canais de Venda - Temu"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/liberacao":{"get":{"summary":"A Shein está liberada para este lojista?","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shein/connect":{"post":{"summary":"Iniciar a autorização da loja Shein (SellerHub)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/shein/callback":{"post":{"summary":"Concluir a autorização da loja Shein (retorno do SellerHub)","tags":["Canais de Venda - Shein"],"description":"Recebe temp_token, state e, quando a Shein manda, appid; confere o app e o state, troca o token temporário, lê a loja e os sites, recusa loja fora da Shein Brasil ou desativada e grava em sales_channels.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["temp_token","state"],"properties":{"temp_token":{"type":"string","minLength":1,"maxLength":512},"state":{"type":"string","minLength":1,"maxLength":2000},"appid":{"type":"string","nullable":true,"maxLength":255}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string"},"external_user_id":{"type":"string"},"region":{"type":"string"}}}}}}}}},"/sales-channels/shein/status":{"get":{"summary":"Status da conexão com a Shein","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true},"autorizacao":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true}}}}}}}}},"/sales-channels/shein/health-check":{"post":{"summary":"Testar a conexão com a Shein","tags":["Canais de Venda - Shein"],"description":"Relê query-store-info e query-site-list: nome, situação, sites e cota. Chave recusada pede reconexão.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/saude":{"get":{"summary":"Saúde operacional do canal Shein","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/config":{"patch":{"summary":"Ligar ou pausar a Shein e gravar a régua de preço","tags":["Canais de Venda - Shein"],"description":"O interruptor (ativo; ativar exige a conexão em ok) e, desde a Rodada 3, a régua de preço da casa (markup_percentual, margem_liquida_percentual, custo_operacao_centavos, buffer_seguranca) e a comissão estimada (comissao_estimada, 0 a 50%): a régua calcula o preço de venda no Shein Brasil. A comissão real vem em cada pedido. Régua e comissão reenviam o preço dos vínculos; buffer, o estoque.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean","nullable":true},"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"comissao_estimada":{"type":"number","minimum":0,"maximum":50,"nullable":true},"nfe":{"type":"object","nullable":true,"additionalProperties":false,"properties":{"icms":{"type":"integer","enum":[1,2,3]},"envio_automatico":{"type":"boolean"}}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/shein/disconnect":{"post":{"summary":"Desconectar a loja Shein","tags":["Canais de Venda - Shein"],"description":"A Shein não tem API de revogar: apaga a chave e a loja da linha (soft-disconnect) e diz o passo no SellerHub.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"supplier_id":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/shein/listings":{"get":{"summary":"Anúncios aprovados da loja na Shein, uma linha por SKU (20 SKCs por página)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","enum":["todas","vinculados","sugeridos","sem_produto","divergentes","a_venda","fora_da_vitrine","parado","fora_do_brasil"]},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":2500},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"anuncios":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"spu_name":{"type":"string"},"skc_name":{"type":"string"},"sku_code":{"type":"string"},"codigo_vendedor":{"type":"string","nullable":true},"codigo_cor":{"type":"string","nullable":true},"titulo":{"type":"string"},"cor":{"type":"string","nullable":true},"tamanho":{"type":"string","nullable":true},"estoque_shein":{"type":"integer","nullable":true},"estoque_por_armazem":{"type":"array","items":{"type":"object","properties":{"armazem":{"type":"string"},"nome":{"type":"string"},"quantidade":{"type":"integer"}}}},"preco_venda":{"type":"number","nullable":true},"preco_especial":{"type":"number","nullable":true},"situacao":{"type":"string"},"vinculo":{"type":"object","additionalProperties":true,"nullable":true},"sugestao":{"type":"object","additionalProperties":true,"nullable":true},"estoque_hub":{"type":"integer","nullable":true},"preco_hub_centavos":{"type":"integer","nullable":true},"divergencia":{"type":"object","additionalProperties":true,"nullable":true},"preco_shein":{"type":"object","nullable":true,"properties":{"situacao":{"type":"string"},"rotulo":{"type":"string"},"alvo":{"type":"number"},"especial_antes":{"type":"number","nullable":true},"motivo":{"type":"string","nullable":true},"enviado_em":{"type":"string"}}},"ultimo_erro":{"type":"string","nullable":true}}}},"proxima_pagina":{"type":"integer","nullable":true},"aviso_so_aprovados":{"type":"string"},"contagem":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/listings/vincular":{"post":{"summary":"Vincular um SKU da Shein a uma variação da loja (ou todos os sugeridos pelo código do vendedor)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sugeridos":{"type":"boolean"},"skc_name":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"sku_code":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"spu_name":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"produto_id":{"type":"string","nullable":true},"variacao_id":{"type":"string","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"vinculados":{"type":"integer"},"na_fila":{"type":"integer"},"listing_id":{"type":"string"},"aviso":{"type":"string","nullable":true},"recusados":{"type":"array","items":{"type":"object","properties":{"sku_code":{"type":"string"},"motivo":{"type":"string"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/listings/{listingId}/sync":{"post":{"summary":"Mandar o estoque (todos os armazéns) e o preço deste vínculo agora, pelo envio da Shein","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"estoque":{"type":"string"},"preco":{"type":"string"},"motivo_preco":{"type":"string","nullable":true},"erro":{"type":"string","nullable":true},"preco_shein":{"type":"object","nullable":true,"properties":{"situacao":{"type":"string"},"rotulo":{"type":"string"},"alvo":{"type":"number"},"especial_antes":{"type":"number","nullable":true},"motivo":{"type":"string","nullable":true},"enviado_em":{"type":"string"}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/listings/{listingId}":{"delete":{"summary":"Desfazer o vínculo (o anúncio continua na Shein)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/listings/{listingId}/preco":{"get":{"summary":"O preço de venda esperado, a revisão da Shein e a trava de campanha","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"preco_esperado":{"type":"number","nullable":true},"preco_shein":{"type":"object","nullable":true,"properties":{"situacao":{"type":"string"},"rotulo":{"type":"string"},"alvo":{"type":"number"},"especial_antes":{"type":"number","nullable":true},"motivo":{"type":"string","nullable":true},"enviado_em":{"type":"string"}}},"trava_campanha":{"type":"integer"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/listings/{listingId}/preco/apagar-promocao":{"post":{"summary":"Mandar o preço novo sem o especial (apaga a promoção na Shein); só com a revisão em \"promocional\"","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"preco_shein":{"type":"object","nullable":true,"properties":{"situacao":{"type":"string"},"rotulo":{"type":"string"},"alvo":{"type":"number"},"especial_antes":{"type":"number","nullable":true},"motivo":{"type":"string","nullable":true},"enviado_em":{"type":"string"}}},"motivo":{"type":"string","nullable":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/importacao":{"post":{"summary":"Pedir a leitura do catálogo aprovado da Shein (a prévia sai em alguns minutos)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"situacao":{"type":"string"},"pedida_em":{"type":"string","nullable":true},"pronta_em":{"type":"string","nullable":true},"lidos":{"type":"integer"},"total":{"type":"integer","nullable":true},"erro":{"type":"string","nullable":true},"confirmados":{"type":"integer"},"previa":{"type":"object","properties":{"casados":{"type":"array","items":{"type":"object","additionalProperties":true}},"sem_par":{"type":"array","items":{"type":"object","additionalProperties":true}},"ambiguos":{"type":"array","items":{"type":"object","additionalProperties":true}},"sem_codigo":{"type":"array","items":{"type":"object","additionalProperties":true}},"totais":{"type":"object","additionalProperties":true}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"get":{"summary":"O estado da leitura do catálogo e a prévia (casados, sem par, ambíguos, sem código)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"situacao":{"type":"string"},"pedida_em":{"type":"string","nullable":true},"pronta_em":{"type":"string","nullable":true},"lidos":{"type":"integer"},"total":{"type":"integer","nullable":true},"erro":{"type":"string","nullable":true},"confirmados":{"type":"integer"},"previa":{"type":"object","properties":{"casados":{"type":"array","items":{"type":"object","additionalProperties":true}},"sem_par":{"type":"array","items":{"type":"object","additionalProperties":true}},"ambiguos":{"type":"array","items":{"type":"object","additionalProperties":true}},"sem_codigo":{"type":"array","items":{"type":"object","additionalProperties":true}},"totais":{"type":"object","additionalProperties":true}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/importacao/confirmar":{"post":{"summary":"Criar os vínculos dos SKUs casados da prévia (todos, ou só os `sku_code` informados)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"skus":{"type":"array","maxItems":5000,"items":{"type":"string","minLength":1}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"vinculados":{"type":"integer"},"na_fila":{"type":"integer"},"pela_fila":{"type":"boolean"},"aviso":{"type":"string","nullable":true},"recusados":{"type":"array","items":{"type":"object","properties":{"sku_code":{"type":"string"},"motivo":{"type":"string"}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/armazens":{"get":{"summary":"Os armazéns do vendedor na Shein que vendem no Brasil (o certificado fica de fora)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"boolean"},"in":"query","name":"atualizar","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"armazens":{"type":"array","items":{"type":"object","properties":{"codigo":{"type":"string"},"nome":{"type":"string"},"padrao_brasil":{"type":"boolean"}}}},"aviso":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/locais":{"get":{"summary":"Os depósitos que abastecem cada armazém da Shein","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"armazens":{"type":"object","additionalProperties":{"type":"object","properties":{"depositos":{"type":"array","items":{"type":"string"}}}}},"comissao_estimada":{"type":"number","nullable":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"put":{"summary":"Definir os depósitos de cada armazém da Shein (substitui o conjunto; um depósito em um armazém só)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["armazens"],"additionalProperties":false,"properties":{"armazens":{"type":"object","maxProperties":50,"additionalProperties":{"type":"object","required":["depositos"],"additionalProperties":false,"properties":{"depositos":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"armazens":{"type":"object","additionalProperties":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/pedidos/{pedidoId}/repasse":{"get":{"summary":"O repasse da Shein do pedido (os lançamentos do extrato), como está gravado","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"estimado_centavos":{"type":"integer","nullable":true},"lancamentos":{"type":"array","items":{"type":"object","additionalProperties":true}},"liquido_centavos":{"type":"integer"},"repasse":{"type":"object","additionalProperties":true,"nullable":true},"lido_em":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/pedidos/{pedidoId}/repasse/atualizar":{"post":{"summary":"Consultar os lançamentos do pedido na Shein agora (no máximo uma vez a cada 10 minutos)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"estimado_centavos":{"type":"integer","nullable":true},"lancamentos":{"type":"array","items":{"type":"object","additionalProperties":true}},"liquido_centavos":{"type":"integer"},"repasse":{"type":"object","additionalProperties":true,"nullable":true},"lido_em":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/lancamentos/{checkOrderNo}":{"get":{"summary":"Um lançamento do extrato da Shein, por SKU (lido na hora)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"in":"path","name":"checkOrderNo","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"check_order_no":{"type":"string"},"bz_order_no":{"type":"string","nullable":true},"tipo":{"type":"integer","nullable":true},"tipo_rotulo":{"type":"string"},"sinal":{"type":"string"},"valor_centavos":{"type":"integer"},"situacao":{"type":"integer","nullable":true},"situacao_rotulo":{"type":"string"},"previsto_para":{"type":"string","nullable":true},"pago_em":{"type":"string","nullable":true},"repasse_no":{"type":"string","nullable":true},"pedido_original":{"type":"string","nullable":true},"gnre_centavos":{"type":"integer","nullable":true},"tarifa_servico_centavos":{"type":"integer","nullable":true},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/repasses":{"get":{"summary":"Os repasses semanais da Shein e os lançamentos sem pedido","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"repasses":{"type":"array","items":{"type":"object","properties":{"numero":{"type":"string"},"situacao":{"type":"string"},"pago_em":{"type":"string","nullable":true},"metodo":{"type":"string","nullable":true},"soma_centavos":{"type":"integer"},"lancamentos":{"type":"integer"}}}},"avulsos":{"type":"array","items":{"type":"object","properties":{"check_order_no":{"type":"string"},"tipo_rotulo":{"type":"string"},"sinal":{"type":"string"},"valor_centavos":{"type":"integer"},"previsto_para":{"type":"string","nullable":true}}}},"proxima_pagina":{"type":"integer","nullable":true}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/requisitos":{"get":{"summary":"Se a loja pode publicar na Shein (KYC, endereços, finanças), a cota do mês, a cota de vitrine, as marcas e os armazéns","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/produtos":{"get":{"summary":"Os produtos do Hub com a situação na Shein (20 por página)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":10000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/preparar/{produtoId}":{"get":{"summary":"Tudo da tela do produto: categoria (sugerida), padrão, marcas, eixos, cores com fotos e SKUs, formulário, medidas, cota e bloqueios","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/categorias":{"get":{"summary":"Um nível da árvore de categorias DA LOJA na Shein (sem `pai`, a raiz); só a folha publica","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"query","name":"pai","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/categorias/busca":{"get":{"summary":"Busca por nome entre as folhas da árvore da loja (até 30, com o caminho)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","maxLength":100},"in":"query","name":"texto","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/categorias/sugestao":{"get":{"summary":"A categoria sugerida pela Shein a partir da foto principal e do título, só entre as da loja (vazio: a tela abre a árvore)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"query","name":"produto_id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/categorias/{id}/atributos":{"get":{"summary":"O formulário dos atributos da categoria (folha), com o selo alfândega e as regras","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,24}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/categorias/atualizar":{"post":{"summary":"Atualizar categorias: apaga o cache da árvore e dos atributos desta loja (a Shein muda categorias todo mês)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/{produtoId}/respostas":{"put":{"summary":"Gravar as respostas do lojista (categoria, marca, eixos e valores, atributos, medidas, textos no idioma padrão, quantidade, embalagem)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["categoria_id"],"properties":{"categoria_id":{"type":"string","nullable":true,"pattern":"^[0-9]{1,24}$"},"marca_codigo":{"type":"string","nullable":true,"maxLength":100},"eixos":{"type":"array","maxItems":5,"items":{"type":"object","required":["eixo_hub","atributo_id"],"properties":{"eixo_hub":{"type":"string","maxLength":100},"atributo_id":{"type":"string","pattern":"^[0-9]{1,24}$"}}}},"valores":{"type":"array","maxItems":2000,"items":{"type":"object","required":["eixo_hub","valor_hub"],"properties":{"eixo_hub":{"type":"string","maxLength":100},"valor_hub":{"type":"string","maxLength":200},"valor_id":{"type":"string","pattern":"^[0-9]{1,24}$"},"valor_proprio":{"type":"string","maxLength":200}}}},"atributos":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"valor_ids":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[0-9]{1,24}$"}},"texto":{"type":"string","maxLength":1000},"percentuais":{"type":"object","maxProperties":50,"additionalProperties":{"type":"number","minimum":0,"maximum":100}}}}},"atributos_por_sku":{"type":"object","maxProperties":2000,"additionalProperties":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"valor_ids":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[0-9]{1,24}$"}},"texto":{"type":"string","maxLength":1000},"percentuais":{"type":"object","maxProperties":50,"additionalProperties":{"type":"number","minimum":0,"maximum":100}}}}}},"medidas":{"type":"object","maxProperties":100,"additionalProperties":{"type":"object","maxProperties":200,"additionalProperties":{"type":"number"}}},"textos_idioma_padrao":{"type":"object","properties":{"titulo":{"type":"string","maxLength":1000},"descricao":{"type":"string","maxLength":5000}}},"quantidade":{"type":"object","properties":{"tipo":{"type":"number"},"unidade":{"type":"number"},"quantidade":{"type":"number"}}},"embalagem":{"type":"number"}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/{produtoId}/conferir":{"post":{"summary":"Conferir antes de enviar: checagens locais e as leituras da Shein que não criam nada (permissão, cota, códigos repetidos)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub na Shein (uma chamada só: a Shein não tem idempotência)","tags":["Canais de Venda - Shein"],"description":"Trava por produto, estado `enviando` antes da chamada, uma chamada ao `publishOrEdit` sem retentativa (falha que pode ter criado vira `incerta`), resposta gravada antes do vínculo (uma linha por SKU, `revisao: pendente`). 422 `shein_confirmar_cota` sem `confirmo_cota` com a cota controlada; 409 `shein_publicacao_em_andamento`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","minLength":1,"maxLength":64},"colocar_a_venda":{"type":"boolean"},"confirmo_cota":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicar/{produtoId}/reenviar":{"post":{"summary":"Reenviar (só `falhou` ou `incerta`): os códigos são conferidos antes; já na Shein, `recebido_sem_resposta` e nada é reenviado","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/{produtoId}/codigo-shein":{"post":{"summary":"O lojista informa o SPU que aparece no SellerHub (conferido com a revisão da Shein antes de gravar)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["spu_name"],"properties":{"spu_name":{"type":"string","pattern":"^\\s*[A-Za-z0-9_-]{1,64}\\s*$"}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/situacao/{produtoId}":{"get":{"summary":"A situação da publicação por cor (revisão e vitrine do Shein Brasil), relida da Shein enquanto ela decide","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/{produtoId}/vitrine":{"post":{"summary":"Colocar à venda ou tirar da vitrine do Shein Brasil por cor (20 min por cor entre duas operações: dentro do intervalo, fica agendado)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["estado"],"properties":{"skc_names":{"type":"array","maxItems":40,"items":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}},"estado":{"type":"string","enum":["a_venda","fora"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/publicacao/{produtoId}/corrigir":{"post":{"summary":"Corrigir a cor recusada pelo `partialEdit` (só título, descrição e atributos de produto; uma chamada, sem retentativa)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["skc_name"],"properties":{"skc_name":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"titulo":{"type":"string","maxLength":1000},"descricao":{"type":"string","maxLength":5000},"atributos":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"valor_ids":{"type":"array","maxItems":50,"items":{"type":"string","pattern":"^[0-9]{1,24}$"}},"texto":{"type":"string","maxLength":1000},"percentuais":{"type":"object","maxProperties":50,"additionalProperties":{"type":"number","minimum":0,"maximum":100}}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/shein/pedidos/{pedidoId}/despacho":{"get":{"summary":"Envio pela Shein: divisão do pacote, NF-e, CT-e, etiqueta, coleta, rastreio e o que a loja pode fazer","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","maxLength":5},"in":"query","name":"atualizar","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/divisao":{"post":{"summary":"Confirma ou cancela a divisão do pacote sugerida pela Shein (irreversível; uma chamada, sem retentativa)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["decisao"],"properties":{"decisao":{"type":"string","enum":["confirmar","cancelar"]},"confirmo":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/nota-fiscal":{"post":{"summary":"Envia a NF-e à Shein (a nota do pedido, ou o XML anexado), com pré-checagem; a Shein confere e emite o CT-e","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/nota-fiscal/reenviar":{"post":{"summary":"Reenvia a NF-e que a Shein pediu (a nota emitida mais recente do pedido)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"alvo":{"type":"string","maxLength":64,"nullable":true},"confirmo_mesma_nota":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/etiqueta":{"post":{"summary":"Gera a etiqueta da Shein (PDF guardado na Varejo Hub); só com o CT-e emitido","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"pacotes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":64},"maxItems":50}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O PDF guardado da etiqueta (gerado de novo quando falta e o pedido ainda não foi coletado)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"query","name":"pacote","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/rastreio/atualizar":{"post":{"summary":"Relê o rastreio de cada pacote na Shein (no máximo uma vez a cada 10 min)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos-a-despachar":{"get":{"summary":"Os pedidos da Shein a despachar, por passo (teto 500)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","maxLength":20},"in":"query","name":"passo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/notas-em-lote":{"post":{"summary":"Envia a NF-e de vários pedidos à Shein (os que não puderam saem com o motivo)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/etiquetas-em-lote":{"post":{"summary":"Gera a etiqueta de vários pedidos, um por vez (os sem CT-e saem com o motivo)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/etiquetas-em-lote/arquivo":{"post":{"summary":"Um ZIP com as etiquetas guardadas dos pedidos (X-Shein-Sem-Etiqueta: os que ficaram de fora)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/posvenda":{"get":{"summary":"Cancelamentos e devolução do pedido da Shein: peças canceladas com o motivo, falta de estoque, reembolso depois do envio e ocorrência","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/pedidos/{pedidoId}/falta-de-estoque":{"post":{"summary":"Confirma falta de estoque de peças do pedido na Shein (uma chamada por peça; pode gerar penalidade para a loja)","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["linhas"],"properties":{"linhas":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["sku_code","pecas"],"properties":{"sku_code":{"type":"string","minLength":1,"maxLength":64},"pecas":{"type":"integer","minimum":1,"maximum":500}}}},"confirmo_penalidade":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/devolucoes-a-conferir":{"get":{"summary":"Devoluções da Shein que chegaram ou foram assinadas e ainda não entraram no estoque (teto 500)","tags":["Canais de Venda - Shein"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/devolucoes/{devolucaoId}":{"get":{"summary":"A devolução da Shein lida na hora: peças, valores, nota, logística de volta, a ação do momento e o estoque","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/devolucoes/{devolucaoId}/fotos":{"get":{"summary":"As fotos e vídeos do comprador, lidos na hora na Shein (nunca gravados)","tags":["Canais de Venda - Shein"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/shein/devolucoes/{devolucaoId}/receber":{"post":{"summary":"Recebi o pacote: assina o recebimento na Shein (irreversível) e devolve as peças ao estoque, uma vez só","tags":["Canais de Venda - Shein"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmo":{"type":"boolean"},"chegou_antes_do_aviso":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/listings":{"get":{"summary":"Anúncios da loja na Dafiti: um grupo por cor (ProductSet) e uma linha por tamanho (20 cores por página)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":40},"in":"query","name":"situacao","required":false},{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":5000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/listings/vincular":{"post":{"summary":"Vincular um tamanho da Dafiti a uma variação da loja (ou todos os sugeridos pelo código do vendedor)","tags":["Canais de Venda - Dafiti"],"description":"A Varejo Hub não muda nada na Dafiti. Uma variação da loja liga a um tamanho só (409 dafiti_variacao_ja_vinculada).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sugeridos":{"type":"boolean"},"product_set_id":{"type":["string","integer"],"pattern":"^[0-9]{1,20}$"},"product_id":{"type":["string","integer"],"pattern":"^[0-9]{1,20}$"},"produto_id":{"type":"string","nullable":true},"variacao_id":{"type":"string","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/listings/{listingId}/sync":{"post":{"summary":"Mandar o estoque e o preço deste tamanho agora (mesmo sem mudança), pelo envio da Dafiti","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/listings/{listingId}":{"delete":{"summary":"Desfazer o vínculo (o anúncio continua na Dafiti)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"500":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/listings/{listingId}/preco":{"get":{"summary":"O preço cheio esperado, a comissão do contrato com a origem e a promoção do Seller Center","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/listings/{listingId}/preco/encerrar-promocao":{"post":{"summary":"Mandar o preço novo e encerrar a promoção do Seller Center (salePrice: null); só com o preço esperando a confirmação","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"listingId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/importacao":{"post":{"summary":"Pedir a leitura do catálogo da Dafiti (a prévia sai em alguns minutos)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"get":{"summary":"O estado da leitura do catálogo e a prévia (casados, sem par, ambíguos e já vinculados)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/importacao/confirmar":{"post":{"summary":"Criar os vínculos dos tamanhos casados da prévia (todos, ou só os `product_ids` informados) e mandar o estoque","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"product_ids":{"type":"array","maxItems":5000,"items":{"type":["string","integer"]}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/locais":{"get":{"summary":"Depósitos que abastecem a Dafiti (a soma deles vai a cada tamanho)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Definir os depósitos da Dafiti (substitui o conjunto)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["locais"],"additionalProperties":false,"properties":{"locais":{"type":"array","maxItems":50,"items":{"type":"string","minLength":1}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/comissoes":{"get":{"summary":"A comissão do contrato lida do Seller Center (geral, por categoria, por marca e as regras que a régua ainda não usa)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"nullable":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/comissoes/ler":{"post":{"summary":"Ler de novo a comissão do contrato no Seller Center (no máximo uma vez por minuto)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"nullable":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/repasse":{"get":{"summary":"O repasse da Dafiti do pedido (comissão, tarifas, impostos e o valor a receber por peça), como está gravado","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"nullable":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/repasse/atualizar":{"post":{"summary":"Ler o repasse do pedido na Dafiti agora (no máximo uma vez a cada 10 minutos)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/repasses":{"get":{"summary":"Os extratos da Dafiti lidos (número, período, vencimento, pago ou a pagar, valor e a fatura de comissão)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/repasses/{extratoId}":{"get":{"summary":"O detalhe de um extrato da Dafiti, lido na hora (os grupos com o nome e o valor como vieram)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,20}$"},"in":"path","name":"extratoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/requisitos":{"get":{"summary":"Se a loja pode publicar na Dafiti (ativa, no ar, depósitos), o ambiente e o agrupamento de cores","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/produtos":{"get":{"summary":"Os produtos do Hub com a situação na Dafiti (20 por página)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":200},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":10000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/preparar/{produtoId}":{"get":{"summary":"Tudo da tela do produto: categoria, marca, formulário, tamanhos, cores (título, descrição, fotos, SKUs, preço, estoque, medidas), bloqueios e avisos","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/categorias":{"get":{"summary":"Um nível da árvore de categorias da Dafiti (sem `pai`, a raiz); só a folha publica","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,12}$"},"in":"query","name":"pai","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/categorias/busca":{"get":{"summary":"Busca por nome entre as folhas da árvore (até 30, com o caminho)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":100},"in":"query","name":"texto","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/categorias/{id}/atributos":{"get":{"summary":"O formulário dos atributos da categoria (pelo `id` da categoria escolhida)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,12}$"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/categorias/atualizar":{"post":{"summary":"Atualizar categorias: apaga o cache da árvore, dos atributos e das regras desta loja no ambiente conectado","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/marcas":{"get":{"summary":"As marcas da Dafiti (busca por nome, 100 por página) com o selo de restrita e a liberação da loja","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":100},"in":"query","name":"nome","required":false},{"schema":{"type":"integer","minimum":1,"maximum":1000},"in":"query","name":"pagina","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/{produtoId}/respostas":{"put":{"summary":"Gravar as respostas do lojista (categoria, segunda categoria, marca, atributos, tamanhos, títulos, fotos ajustadas, cor da Dafiti por cor)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"categoria_id":{"type":["integer","string","null"]},"segunda_categoria_id":{"type":["integer","string","null"]},"marca_id":{"type":["integer","string","null"]},"atributos":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"opcao_id":{"type":["integer","string"]},"opcao_ids":{"type":"array","maxItems":100,"items":{"type":["integer","string"]}},"texto":{"type":"string","maxLength":5000}}}},"tamanhos":{"type":"array","maxItems":500,"items":{"type":"object","required":["valor_hub"],"properties":{"valor_hub":{"type":"string","maxLength":200},"valor_dafiti":{"type":["string","null"],"maxLength":200}}}},"titulos":{"type":"object","maxProperties":200,"additionalProperties":{"type":"string","maxLength":1000}},"usar_fotos_ajustadas":{"type":"object","maxProperties":200,"additionalProperties":{"type":"boolean"}},"cores_dafiti":{"type":"object","maxProperties":200,"additionalProperties":{"type":["integer","string"]}}}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/{produtoId}/fotos/ajustar":{"post":{"summary":"Gera a cópia de cada foto fora do padrão da cor (1000 a 1104 x 1000 a 1600, fundo branco), guardada para a prévia","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cor_hub"],"properties":{"cor_hub":{"type":"string","minLength":1,"maxLength":200}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/{produtoId}/conferir":{"post":{"summary":"Conferir antes de enviar: as checagens locais e as leituras da Dafiti que não criam nada (a loja, os SKUs que já existem)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicar":{"post":{"summary":"Publicar um produto da Varejo Hub na Dafiti (um ProductSet por cor, por passos, sem idempotência)","tags":["Canais de Venda - Dafiti"],"description":"Trava por produto, estado gravado antes de cada chamada, a consulta do SKU antes de criar, as fotos uma a uma depois do intervalo. 422 `dafiti_confirmar_cq` sem `confirmo_cq`; 422 `dafiti_publicacao_bloqueada` com os bloqueios; 409 `dafiti_publicacao_em_andamento`.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","minLength":1,"maxLength":64},"confirmo_cq":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicar/{produtoId}/continuar":{"post":{"summary":"Continuar a publicação parada (ou a que falhou, com respostas novas) do passo gravado de cada cor","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/situacao/{produtoId}":{"get":{"summary":"A situação da publicação por cor (passo, controle de qualidade, visibilidade), relida da Dafiti no máximo uma vez por minuto","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/publicacao/{produtoId}/corrigir":{"post":{"summary":"Corrigir e reenviar a cor recusada (só o que mudou, uma chamada; as fotos com `overwrite`)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cor_hub"],"properties":{"cor_hub":{"type":"string","minLength":1,"maxLength":200},"titulo":{"type":"string","maxLength":1000},"descricao":{"type":"string","maxLength":20000},"segunda_categoria_id":{"type":["integer","string","null"]},"atributos":{"type":"object","maxProperties":300,"additionalProperties":{"type":"object","additionalProperties":false,"properties":{"opcao_id":{"type":["integer","string"]},"opcao_ids":{"type":"array","maxItems":100,"items":{"type":["integer","string"]}},"texto":{"type":"string","maxLength":5000}}}},"fotos":{"type":"array","maxItems":8,"items":{"type":"object","required":["posicao"],"properties":{"posicao":{"type":"integer","minimum":1,"maximum":8},"usar_ajustada":{"type":"boolean"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":64},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/despacho":{"get":{"summary":"Envio pela Dafiti: modo, pacotes, NF-e, etiqueta, coleta, enviado e entregue, e o que a loja pode fazer","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":5},"in":"query","name":"atualizar","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/despacho/modo":{"post":{"summary":"Troca o modo de envio do pedido (Dafiti Envios ou uma transportadora da lista da Dafiti), só antes do primeiro envio","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["modo"],"properties":{"modo":{"type":"string","enum":["dafiti_envios","transportadora_propria"]},"transportadora_uuid":{"type":"string","maxLength":64,"nullable":true}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/nota-fiscal":{"post":{"summary":"Confere a NF-e do pacote (a nota do pedido, ou o XML anexado) antes do envio à Dafiti; nada vai à Dafiti aqui","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/enviar":{"post":{"summary":"Envia o pacote à Dafiti (o pronto para envio com a NF-e); depois disso o pedido não pode mais ser cancelado por falta de estoque","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","maxItems":200,"items":{"type":"string","pattern":"^[0-9]{1,20}$"}},"transportadora_uuid":{"type":"string","maxLength":64,"nullable":true},"rastreio":{"type":"string","maxLength":64,"nullable":true},"confirmo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/etiqueta":{"post":{"summary":"Gera a etiqueta da Dafiti (Dafiti Envios e Milkrun; assíncrona, o PDF guardado na Varejo Hub)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"pacote":{"type":"string","pattern":"^[0-9]{1,20}$","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"get":{"summary":"O PDF guardado da etiqueta (gerado de novo quando falta e o pacote ainda não foi coletado)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9]{1,20}$"},"in":"query","name":"pacote","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/coleta":{"post":{"summary":"Solicita a coleta (Dafiti Envios: a coleta; Milkrun: o manifesto)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"pacote":{"type":"string","pattern":"^[0-9]{1,20}$","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/enviado":{"post":{"summary":"Marca o pacote como enviado na Dafiti (só transportadora própria)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"pacote":{"type":"string","pattern":"^[0-9]{1,20}$","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/entregue":{"post":{"summary":"Marca o pacote como entregue na Dafiti (só transportadora própria)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"pacote":{"type":"string","pattern":"^[0-9]{1,20}$","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/nota-fiscal/corrigir":{"post":{"summary":"Troca a NF-e do pacote na Dafiti depois do envio (a nota reemitida mais recente do pedido)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pacote":{"type":"string","pattern":"^[0-9]{1,20}$","nullable":true},"confirmo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/transportadoras":{"get":{"summary":"As transportadoras cadastradas na Dafiti para a loja (memória de 1 h)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos-a-despachar":{"get":{"summary":"Os pedidos da Dafiti a despachar, por passo (teto 500)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","maxLength":30},"in":"query","name":"passo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/enviar-em-lote":{"post":{"summary":"Envia vários pedidos à Dafiti (os que não puderam saem com o motivo)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500},"confirmo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/etiquetas-em-lote/arquivo":{"post":{"summary":"Um ZIP com as etiquetas guardadas dos pedidos (X-Dafiti-Sem-Etiqueta: os que ficaram de fora)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500},"confirmo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/coleta-em-lote":{"post":{"summary":"Solicita a coleta de vários pedidos (o Dafiti Envios numa chamada por 100 itens; o Milkrun, o manifesto)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500},"confirmo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/enviados-em-lote":{"post":{"summary":"Marca vários pedidos como enviados (só transportadora própria)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_ids"],"properties":{"pedido_ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500},"confirmo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/posvenda":{"get":{"summary":"Cancelamentos e devolução do pedido da Dafiti: peças canceladas com o motivo, cancelar por falta de estoque, falha na entrega e devoluções","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/cancelar":{"post":{"summary":"Cancela peças do pedido na Dafiti por falta de estoque (só peça a processar; o motivo é o da Dafiti; pode cancelar o pacote inteiro)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["linhas"],"properties":{"linhas":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["seller_sku","pecas"],"properties":{"seller_sku":{"type":"string","minLength":1,"maxLength":200},"pecas":{"type":"integer","minimum":1,"maximum":500}}}},"confirmo":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/falha-na-entrega":{"post":{"summary":"A entrega falhou: marca na Dafiti as peças enviadas que voltaram (status final), com a opção de devolver ao estoque","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"itens":{"type":"array","items":{"type":"string","pattern":"^[0-9]{1,20}$"},"maxItems":200},"motivo_nome":{"type":"string","maxLength":200},"detalhe":{"type":"string","maxLength":500,"nullable":true},"pacote_voltou":{"type":"boolean"},"repor_estoque":{"type":"boolean"},"tentar_de_novo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/pedidos/{pedidoId}/marcar-devolvido":{"post":{"summary":"Marca como devolvidas peças entregues do pedido na Dafiti (cria a devolução; o estoque só volta com o \"Recebi o pacote\")","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["itens"],"properties":{"itens":{"type":"array","items":{"type":"string","pattern":"^[0-9]{1,20}$"},"minItems":1,"maxItems":200},"motivo_nome":{"type":"string","maxLength":200,"nullable":true},"confirmo":{"type":"boolean"},"tentar_de_novo":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/motivos":{"get":{"summary":"Os motivos ativos da Dafiti por tipo (o nome é o que vai à Dafiti)","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","enum":["canceled","failed","return_rejected","returned"]},"in":"query","name":"tipo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/devolucoes-a-conferir":{"get":{"summary":"Devoluções da Dafiti a caminho, entregues, em falha ou concluídas que ainda não entraram no estoque (teto 500)","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/devolucoes/{devolucaoId}":{"get":{"summary":"A devolução da Dafiti lida na hora: a peça, as irmãs do pedido, o rastreio da volta, a ação do momento e o estoque","tags":["Canais de Venda - Dafiti"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/devolucoes/{devolucaoId}/receber":{"post":{"summary":"Recebi o pacote (ou Confirmar entrada no estoque): registra o recebimento na Dafiti quando ela permite e devolve as peças ao estoque, uma vez só","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmo":{"type":"boolean"},"chegou_antes_da_aprovacao":{"type":"boolean"},"junto":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":50},"tentar_de_novo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/devolucoes/{devolucaoId}/aprovar":{"post":{"summary":"Aprova a devolução na Dafiti (quando a conta permite)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmo":{"type":"boolean"},"motivo_nome":{"type":"string","maxLength":200},"detalhe":{"type":"string","maxLength":500,"nullable":true},"tentar_de_novo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/devolucoes/{devolucaoId}/recusar":{"post":{"summary":"Recusa a devolução na Dafiti com o motivo da lista dela (quando a conta permite)","tags":["Canais de Venda - Dafiti"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"confirmo":{"type":"boolean"},"motivo_nome":{"type":"string","maxLength":200},"detalhe":{"type":"string","maxLength":500,"nullable":true},"tentar_de_novo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"devolucaoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/liberacao":{"get":{"summary":"A Dafiti está liberada para este lojista?","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/dafiti/conectar":{"post":{"summary":"Conectar a loja Dafiti com o Application ID e o Secret do Seller Center","tags":["Canais de Venda - Dafiti"],"description":"O lojista cria um aplicativo em Configurações > Gerenciamento de integrações > Aplicativos OAuth e cola o par. Pede o token, lê a loja (GET /v2/seller), recusa loja inativa e loja de outra conta, grava e cria o aviso.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["client_id","client_secret"],"properties":{"client_id":{"type":"string","maxLength":1000},"client_secret":{"type":"string","maxLength":1000}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string"},"aviso":{"type":"string"},"message":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/dafiti/aviso":{"post":{"summary":"Criar o aviso de pedidos da Dafiti de novo","tags":["Canais de Venda - Dafiti"],"description":"Apaga o aviso antigo na Dafiti, gera um segredo novo e cria outro com a URL do canal.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"aviso":{"type":"string"},"message":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/dafiti/status":{"get":{"summary":"Status da conexão com a Dafiti","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true},"aviso":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true},"ambiente":{"type":"string"}}}}}}}}},"/sales-channels/dafiti/health-check":{"post":{"summary":"Testar a conexão com a Dafiti","tags":["Canais de Venda - Dafiti"],"description":"Renova o token se preciso, relê GET /v2/seller e confere o aviso. Credencial recusada pede reconexão; aviso apagado não rebaixa a loja.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/saude":{"get":{"summary":"Saúde operacional do canal Dafiti","tags":["Canais de Venda - Dafiti"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/dafiti/config":{"patch":{"summary":"Ligar ou pausar a Dafiti e gravar a régua de preço","tags":["Canais de Venda - Dafiti"],"description":"O interruptor (ativo; ativar exige a conexão em ok) e, desde a Rodada 3, a régua de preço da casa (markup_percentual, margem_liquida_percentual, custo_operacao_centavos, buffer_seguranca): a régua calcula o preço cheio na Dafiti, com a comissão do contrato lida do Seller Center (não editável). A promoção do Seller Center fica como está. Régua reenvia o preço dos vínculos; buffer, o estoque.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"ativo":{"type":"boolean","nullable":true},"markup_percentual":{"type":"integer","minimum":0,"maximum":500,"nullable":true},"margem_liquida_percentual":{"type":"number","minimum":0,"maximum":99.99,"nullable":true},"custo_operacao_centavos":{"type":"integer","minimum":0,"maximum":10000000,"nullable":true},"buffer_seguranca":{"type":"integer","minimum":0,"maximum":100,"nullable":true},"envio":{"type":"object","nullable":true,"additionalProperties":false,"properties":{"modo_padrao":{"type":"string","enum":["pedido","dafiti_envios","transportadora_propria"]},"transportadora_uuid":{"type":"string","maxLength":64,"nullable":true},"automatico":{"type":"boolean"},"tamanho_etiqueta":{"type":"string","enum":["A4","A6"]}}}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/dafiti/disconnect":{"post":{"summary":"Desconectar a loja Dafiti","tags":["Canais de Venda - Dafiti"],"description":"Apaga o aviso na Dafiti (se falhar, segue), apaga o token e o Secret (soft-disconnect) e diz o passo no Seller Center.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"aviso_apagado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"vendedor_id":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/magalu/liberacao":{"get":{"summary":"O Magalu está liberado para este lojista?","tags":["Canais de Venda - Magalu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"liberado":{"type":"boolean"},"motivo":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/magalu/connect":{"post":{"summary":"Iniciar a autorização da loja no ID Magalu","tags":["Canais de Venda - Magalu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string"},"redirect_uri":{"type":"string"}}}}}}}}},"/sales-channels/magalu/callback":{"post":{"summary":"Concluir a autorização da loja no ID Magalu","tags":["Canais de Venda - Magalu"],"description":"Recebe code + state, troca pelo par de tokens, lê a loja (GET /seller/v1/portfolios/me), recusa quem não é ADMIN, loja de outro canal e loja já conectada em outra conta; grava em sales_channels e inscreve os avisos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string","minLength":1},"state":{"type":"string","minLength":1}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"nickname":{"type":"string","nullable":true},"avisos":{"type":"object","properties":{"inscritos":{"type":"integer"},"total":{"type":"integer"},"falharam":{"type":"array","items":{"type":"string"}}}}}}}}}}}},"/sales-channels/magalu/avisos":{"post":{"summary":"Inscrever de novo os avisos do Magalu","tags":["Canais de Venda - Magalu"],"description":"Reinscreve os tópicos que faltam ({ todos: true } reinscreve todos). Cada inscrição gera um segredo novo; o anterior vale por 1 h.","requestBody":{"content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"todos":{"type":"boolean","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/magalu/status":{"get":{"summary":"Status da conexão com o Magalu","tags":["Canais de Venda - Magalu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string"},"external_user_id":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"site_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"},"nullable":true},"config":{"type":"object","additionalProperties":true},"expires_at":{"type":"string","nullable":true},"last_health_check_at":{"type":"string","nullable":true},"last_health_error":{"type":"string","nullable":true},"last_sync_at":{"type":"string","nullable":true},"conectado_em":{"type":"string"},"webhook_url":{"type":"string","nullable":true},"webhook_secret_configurado":{"type":"boolean"},"region":{"type":"string","nullable":true},"loja":{"type":"object","additionalProperties":true,"nullable":true},"avisos":{"type":"object","additionalProperties":true,"nullable":true},"permissao":{"type":"object","additionalProperties":true,"nullable":true},"autorizacao":{"type":"object","additionalProperties":true,"nullable":true},"ambiente":{"type":"string"}}}}}}}}},"/sales-channels/magalu/health-check":{"post":{"summary":"Testar a conexão com o Magalu","tags":["Canais de Venda - Magalu"],"description":"Renova o token se preciso, relê o me e confere as inscrições. 403 marca \"não é ADMIN\" sem rebaixar; refresh recusado pede reconexão.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/magalu/saude":{"get":{"summary":"Saúde operacional do canal Magalu","tags":["Canais de Venda - Magalu"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/magalu/config":{"patch":{"summary":"Ligar ou pausar o Magalu","tags":["Canais de Venda - Magalu"],"description":"Rodada 1: só o interruptor (ativo). Ativar exige a conexão em ok.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean","nullable":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/magalu/disconnect":{"post":{"summary":"Desconectar a loja do Magalu","tags":["Canais de Venda - Magalu"],"description":"Apaga as inscrições na Magalu (melhor esforço), os tokens e os segredos (soft-disconnect). A Magalu não tem revogação por API.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"revogado":{"type":"boolean"},"motivo":{"type":"string","nullable":true},"tenant_id":{"type":"string","nullable":true},"avisos_apagados":{"type":"integer"},"avisos_nao_apagados":{"type":"integer"}}}}}}}}},"/sales-channels/resumo":{"get":{"summary":"Números e pendências de cada canal conectado do tenant","tags":["Canais de Venda"],"description":"Uma linha por canal conectado: contagem de anúncios por estado, vendas dos últimos 7 dias com variação sobre os 7 anteriores, último evento recebido e as pendências que esperam por alguém. Alimenta o painel de marketplaces e a visão geral de cada canal.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"canais":{"type":"array","items":{"type":"object","properties":{"provider":{"type":"string"},"ativo":{"type":"boolean"},"status":{"type":"string","nullable":true},"external_nickname":{"type":"string","nullable":true},"external_user_id":{"type":"string","nullable":true},"anuncios":{"type":"object","properties":{"publicados":{"type":"integer"},"pausados":{"type":"integer"},"com_erro":{"type":"integer"}}},"pedidos_7d":{"type":"object","properties":{"quantidade":{"type":"integer"},"faturamento_centavos":{"type":"integer"},"variacao_percentual":{"type":"integer","nullable":true}}},"ultimo_evento_at":{"type":"string","nullable":true},"pendencias":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string"},"quantidade":{"type":"integer"},"severidade":{"type":"string","enum":["critico","aviso"]}}}},"indisponivel":{"type":"boolean"}}}}}}}}}}}},"/sales-channels/mercado-livre/listings":{"get":{"summary":"Listar anúncios vinculados (paginado)","tags":["Canais de Venda - Mercado Livre"],"description":"Linhas de sales_channel_listings do tenant + derivados produto_titulo/thumbnail (join produto). Filtros: status (external_status; \"erro\" = erro OU diff pendente; \"com_erro\" = só erro), q (título do produto ou MLB id), tipo, somente_divergencias. Default: updated_at desc.","parameters":[{"schema":{"type":"string","enum":["todos","active","paused","closed","under_review","erro","com_erro"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","enum":["todos","active","paused","closed","under_review","erro","com_erro"]},"in":"query","name":"tab","required":false,"description":"Alias de status (compat UI)"},{"schema":{"type":"string","maxLength":200},"in":"query","name":"q","required":false},{"schema":{"type":"string","enum":["gold_pro","gold_special"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"boolean","default":false},"in":"query","name":"somente_divergencias","required":false},{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"string","enum":["updated_at","created_at","last_sync_at","preco_sync_centavos","estoque_sync","external_status","external_listing_id"]},"in":"query","name":"sort","required":false},{"schema":{"type":"string","enum":["asc","desc"],"default":"desc"},"in":"query","name":"dir","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}},"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"}}}}}}}}},"/sales-channels/mercado-livre/anuncio":{"get":{"summary":"Título, foto e preço de um anúncio, para a tela de atendimento","tags":["Canais de Venda - Mercado Livre"],"description":"Leitura do anúncio no canal, sem depender de vínculo com produto do Hub. Cacheada 10min. Papel mínimo: assistant.","parameters":[{"schema":{"type":"string","minLength":3,"maxLength":40},"in":"query","name":"item_id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"item_id":{"type":"string"},"titulo":{"type":"string","nullable":true},"thumbnail":{"type":"string","nullable":true},"permalink":{"type":"string","nullable":true},"preco_centavos":{"type":"integer","nullable":true},"status":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/mercado-livre/listings/lookup":{"get":{"summary":"Preview de um anúncio do ML por MLB id ou URL","tags":["Canais de Venda - Mercado Livre"],"description":"Extrai o MLB id, chama GET /items/:id com o token do tenant e valida que o anúncio pertence à conta conectada (seller_id). Erros: invalid_input (422), not_found (404), anuncio_outro_vendedor (422).","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":500},"in":"query","name":"external","required":true,"description":"MLB id ou URL do anúncio"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"external_listing_id":{"type":"string"},"titulo":{"type":"string"},"preco_centavos":{"type":"integer"},"thumbnail":{"type":"string"},"external_status":{"type":"string"},"permalink":{"type":"string","nullable":true},"external_listing_type":{"type":"string","nullable":true},"ja_vinculado":{"type":"boolean"},"seller_id":{"type":"string","nullable":true}}}}}}}}},"/sales-channels/mercado-livre/listings/link":{"post":{"summary":"Vincular anúncio ML a um produto da Varejo Hub","tags":["Canais de Venda - Mercado Livre"],"description":"Valida produto/variação do tenant, re-faz lookup no ML (pertencimento ao seller) e cria a linha em sales_channel_listings populando external_* + preco_sync/estoque_sync. Uniques violadas → 409 already_linked.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","external_listing_id","sync_direction"],"additionalProperties":false,"properties":{"produto_id":{"type":"string","minLength":1},"variacao_id":{"type":["string","null"],"minLength":1},"external_listing_id":{"type":"string","minLength":6,"maxLength":500},"sync_direction":{"type":"string","enum":["both","from_rekta","from_channel","manual"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}":{"get":{"summary":"Detalhe de um anúncio vinculado (por MLB id)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}}}}}},"patch":{"summary":"Atualizar overrides e direção de sync do vínculo","tags":["Canais de Venda - Mercado Livre"],"description":"Whitelist: preco_override_centavos (inteiro > 0; null limpa), markup_override_percentual (0-500 inteiro; null limpa), sync_direction.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"preco_override_centavos":{"type":["integer","null"],"minimum":1},"markup_override_percentual":{"type":["integer","null"],"minimum":0,"maximum":500},"sync_direction":{"type":"string","enum":["both","from_rekta","from_channel","manual"]}}}}}},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"reenviado":{"type":"boolean"},"divergente":{"type":"boolean"},"listing":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}}}}}}}},"delete":{"summary":"Desvincular anúncio (apaga só o vínculo local — não toca no ML)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/qualidade":{"get":{"summary":"Nota de qualidade do anúncio no Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"GET /item/:id/performance (SINGULAR — o plural responde 404) devolve `score`, `level`, `calculated_at` e as pendências acionáveis com o texto PT-BR do próprio ML. Custa uma requisição ao ML por chamada: é da tela de detalhe, não da listagem. Anúncio ainda não avaliado volta `disponivel: false` com `nota: null` — ausência não é zero.","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"disponivel":{"type":"boolean"},"nota":{"type":"number","nullable":true},"nivel":{"type":"string","nullable":true},"calculado_em":{"type":"string","nullable":true},"pendencias":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"grupo":{"type":"string","nullable":true},"titulo":{"type":"string","nullable":true},"acoes":{"type":"array","items":{"type":"string"}}}}}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/preco-override":{"patch":{"summary":"Atualizar só o override de preço (alias da UI)","tags":["Canais de Venda - Mercado Livre"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["preco_override_centavos"],"additionalProperties":false,"properties":{"preco_override_centavos":{"type":["integer","null"],"minimum":1}}}}},"required":true},"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"reenviado":{"type":"boolean"},"divergente":{"type":"boolean"},"listing":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/pausar":{"post":{"summary":"Pausar anúncio no ML (PUT /items/:id status=paused)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"external_status":{"type":"string"}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/pause":{"post":{"summary":"Pausar anúncio no ML (alias da UI)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"external_status":{"type":"string"}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/reativar":{"post":{"summary":"Reativar anúncio no ML (PUT /items/:id status=active)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"external_status":{"type":"string"}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/activate":{"post":{"summary":"Reativar anúncio no ML (alias da UI)","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"external_status":{"type":"string"}}}}}}}}},"/sales-channels/mercado-livre/listings/{externalId}/sync":{"post":{"summary":"Reconsultar o anúncio no Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"description":"Re-fetch GET /items/:id e recálculo de last_sync_diff contra o preço esperado e o estoque PUBLICÁVEL (estoque_publicavel_listing — a mesma função que o push usa). O espelho (preco_sync/estoque_sync/external_status) só é gravado quando sync_direction permite inbound (P1-12). Havendo divergência e direção outbound, enfileira o push e devolve reenviado=true (P2-36).","parameters":[{"schema":{"type":"string","minLength":1,"maxLength":300},"in":"path","name":"externalId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"reenviado":{"type":"boolean"},"divergente":{"type":"boolean"},"listing":{"type":"object","properties":{"id":{"type":"string"},"account_id":{"type":"string"},"sales_channel_id":{"type":"string"},"produto_id":{"type":"string"},"variacao_id":{"type":"string","nullable":true},"external_listing_id":{"type":"string"},"external_listing_type":{"type":"string","nullable":true},"external_category_id":{"type":"string","nullable":true},"external_status":{"type":"string","nullable":true},"external_url":{"type":"string","nullable":true},"external_health":{"type":"number","nullable":true},"preco_sync_centavos":{"type":"integer","nullable":true},"estoque_sync":{"type":"integer","nullable":true},"preco_override_centavos":{"type":"integer","nullable":true},"markup_override_percentual":{"type":"integer","nullable":true},"sync_direction":{"type":"string"},"attributes":{"type":"object","additionalProperties":true},"last_sync_at":{"type":"string","nullable":true},"last_sync_error":{"type":"string","nullable":true},"last_sync_diff":{"type":"object","additionalProperties":true,"nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"produto_titulo":{"type":"string"},"thumbnail":{"type":"string"},"estoque_publicavel":{"type":"integer","nullable":true},"estoque_fisico":{"type":"integer","nullable":true},"estoque_retido":{"type":"integer","nullable":true},"logistic_type":{"type":"string","nullable":true},"sub_status":{"type":"array","items":{"type":"string"}}}}}}}}}}}},"/sales-channels/mercado-livre/publicabilidade/resumo":{"get":{"summary":"Resumo de publicabilidade (não exige canal conectado)","tags":["Canais de Venda - Mercado Livre"],"description":"Quantos produtos estão prontos para virar anúncio e o que trava o resto, agrupado por motivo. Custa zero chamada à API do Mercado Livre. Responde 200 mesmo sem canal conectado: é a tela de pré-venda. Papéis: manager, owner, super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicabilidade":{"get":{"summary":"Produtos do lint, paginado","tags":["Canais de Venda - Mercado Livre"],"description":"Lista os produtos de um motivo do lint. Cada linha traz `anuncios_max` (quantos anúncios o produto gera ao publicar, um por variação) e `anuncios_no_ar` (quantos o Mercado Livre já guarda para ele). Produto já publicado CONTINUA na lista, marcado: um produto de grade pode ter 3 de 8 variações no ar e ainda ter 5 para publicar. Papéis: manager, owner, super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"motivo","required":false,"description":"SEM_IMAGEM, TITULO_LONGO, PRONTO..."},{"schema":{"type":"string","enum":["bloqueio","pendencia","pronto"]},"in":"query","name":"severidade","required":false},{"schema":{"type":"string","maxLength":120},"in":"query","name":"busca","required":false},{"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0,"default":0},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicabilidade/titulos/revisar":{"post":{"summary":"Aprovar título para o canal","tags":["Canais de Venda - Mercado Livre"],"description":"Grava o título revisado por uma PESSOA. O banco recusa revisão sem autor (ck_scpp_revisao_tem_pessoa): revisão é gente olhando, não carimbo de LLM.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","titulo"],"properties":{"produto_id":{"type":"string","format":"uuid"},"titulo":{"type":"string","minLength":1,"maxLength":200},"origem":{"type":"string","enum":["manual","llm"],"default":"manual"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicabilidade/titulos/revisar-em-lote":{"post":{"summary":"Aprovar vários títulos de uma vez, cada um com o seu texto","tags":["Canais de Venda - Mercado Livre"],"description":"Grava a revisão de até 50 títulos, todos com a MESMA pessoa como autora. O corpo traz o texto de cada produto: não existe aprovar por filtro, porque revisão sem alguém ter lido é o que o banco recusa (ck_scpp_revisao_tem_pessoa). Papéis: manager, owner, super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["titulos"],"properties":{"titulos":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["produto_id","titulo"],"properties":{"produto_id":{"type":"string","format":"uuid"},"titulo":{"type":"string","minLength":1,"maxLength":200}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicabilidade/fotos/confirmar":{"post":{"summary":"Confirmar que a loja pode usar as fotos do produto","tags":["Canais de Venda - Mercado Livre"],"description":"O lint marca IMAGEM_DE_TERCEIRO quando nenhuma foto vem do storage próprio. Publicar foto de outro site é problema do lojista, não nosso — então a confirmação fica registrada com autor e data.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/preparar/{produtoId}":{"get":{"summary":"Pré-visualiza o anúncio sem escrever nada no Mercado Livre","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/publicar":{"post":{"summary":"Publica os anúncios, respeitando o portão do canário","tags":["Canais de Venda - Mercado Livre"],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/descricoes/preencher":{"post":{"summary":"Preenche a descrição dos anúncios que estão no ar sem nenhuma","tags":["Canais de Venda - Mercado Livre"],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/categoria":{"put":{"summary":"Guarda a categoria escolhida por uma pessoa para este produto","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/titulo":{"put":{"summary":"Guarda o título que uma pessoa escreveu para este anúncio","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/atributos":{"put":{"summary":"Guarda os campos que uma pessoa preencheu para este produto","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/campos-faltantes":{"get":{"summary":"Os campos que o Mercado Livre ainda pede neste produto","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/anuncio":{"put":{"summary":"Guarda o tipo de anúncio e a descrição escolhidos por uma pessoa","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/perfis":{"get":{"summary":"Tipos de produto já publicados e o estado de cada canário","tags":["Canais de Venda - Mercado Livre"],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/perfis/{perfilId}/conferir":{"post":{"summary":"Aprova ou reprova o primeiro anúncio de um tipo de produto","tags":["Canais de Venda - Mercado Livre"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"perfilId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/categorias/sugestoes":{"get":{"summary":"Sugere categorias do Mercado Livre a partir de uma descrição livre","tags":["Canais de Venda - Mercado Livre"],"description":"Recebe o texto que a pessoa escreveu e devolve as categorias que o Mercado Livre reconhece. Endpoint público do ML: não gasta o token do lojista.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/categorias/{categoryId}":{"get":{"summary":"Detalhe de uma categoria: caminho, limites e o que ela exige","tags":["Canais de Venda - Mercado Livre"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"categoryId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/sales-channels/mercado-livre/publicacao/produtos/{produtoId}/historico":{"get":{"summary":"A trilha de publicação de um produto e o anúncio que está no ar","tags":["Canais de Venda - Mercado Livre"],"description":"Uma entrada por tentativa, em ordem decrescente, com a categoria usada e o que o Mercado Livre respondeu em português. Junto vem o anúncio vivo, quando existe, com o preço e o estoque que estão lá contra os nossos. Não gasta o token do lojista, salvo pela consulta pública de nome de categoria, que é servida do cache.","security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/webhook/mercado-livre":{"post":{"summary":"Receber webhook do Mercado Livre","tags":["Webhooks - Mercado Livre"],"description":"Rota pública SEM JWT e SEM params — é a notification URL única da aplicação ML da plataforma. O tenant é resolvido por sales_channels.external_user_id = body.user_id. Endpoint anônimo: application_id filtra notificação de outra aplicação, mas NÃO autentica origem (client_id é público). Idempotência via UNIQUE (account_id, provider, event_id). Processamento em background via fila sc.inbound.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"_id":{"type":"string"},"resource":{"type":"string"},"user_id":{"type":["string","number"]},"topic":{"type":"string"},"application_id":{"type":["string","number"]},"attempts":{"type":"integer"},"sent":{"type":"string"},"received":{"type":"string"}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"duplicate":{"type":"boolean"},"reason":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"error":{"type":"string"}}}}}}}}},"/webhook/shopee":{"post":{"summary":"Receber push da Shopee","tags":["Webhooks - Shopee"],"description":"Rota pública SEM JWT e SEM params, é a callback URL única do app Shopee da plataforma. O tenant é resolvido por sales_channels.external_user_id = body.shop_id (provider shopee). HMAC do corpo cru em observação (SHOPEE_PUSH_HMAC_MODO). Responde 2xx vazio sempre. Idempotência por chave DERIVADA do conteúdo (external_event_id). Processamento na fila sc.inbound.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"code":{"type":"integer"},"shop_id":{"type":["integer","string"]},"timestamp":{"type":"integer"},"data":{"type":["object","array"]}}}}}},"responses":{"200":{"description":"Default Response"}}}},"/webhook/tiktok-shop":{"post":{"summary":"Receber webhook do TikTok Shop","tags":["Webhooks - TikTok Shop"],"description":"Rota pública, sem JWT, uma para todos os lojistas. HMAC do corpo cru no cabeçalho Authorization (bloqueante: 401 quando não confere). Dedup por tts_notification_id. 503 quando não gravou, para o TikTok retentar.","responses":{"200":{"description":"Default Response"}}}},"/webhook/temu":{"post":{"summary":"Receber aviso da Temu","tags":["Webhooks - Temu"],"description":"Rota pública, sem JWT, uma para todos os lojistas. eventData cifrado (AES) e assinado (HMAC-SHA256 em x-tm-signature, bloqueante: 401 quando não confere). Dedup pelo evento e o dado decifrado. 503 quando não gravou.","responses":{"200":{"description":"Default Response"}}}},"/webhook/shein":{"post":{"summary":"Receber aviso da Shein","tags":["Webhooks - Shein"],"description":"Rota pública, sem JWT, uma para todos os lojistas. Assinatura do app em x-lt-signature (bloqueante: 401), eventData cifrado (AES) em multipart, urlencoded ou JSON. Dedup pela loja e o dado decifrado. 503 quando não gravou.","responses":{"200":{"description":"Default Response"}}}},"/webhook/dafiti/{canalId}/{segredo}":{"post":{"summary":"Receber aviso da Dafiti","tags":["Webhooks - Dafiti"],"description":"Rota pública, sem JWT, uma URL por loja com o id do canal e um segredo (conferido pelo hash, em tempo constante). Corpo { event, payload }. Dedup pela chave derivada do evento. 503 quando não gravou.","parameters":[{"schema":{"type":"string"},"in":"path","name":"canalId","required":true},{"schema":{"type":"string"},"in":"path","name":"segredo","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/webhook/magalu":{"post":{"summary":"Receber aviso do Magalu","tags":["Webhooks - Magalu"],"description":"Rota pública, sem JWT, uma para todos os sellers. HMAC-SHA256 do corpo cru em X-Signature-256 com o segredo da inscrição do tópico (bloqueante: 401), X-Timestamp de até 5 min. Tenant desconhecido: 200 sem gravar. Dedup pela chave derivada do aviso. 503 quando não gravou.","responses":{"200":{"description":"Default Response"}}}},"/internal/sales-channels/mercado-livre/responder":{"post":{"summary":"Responder pergunta/mensagem ML (service-to-service)","tags":["Canais de Venda - Mercado Livre (interno)"],"description":"Rota interna Connect → core. Autentica via x-internal-key. Resolve token + seller_id do tenant, sanitiza o texto (350 chars + ISO-8859-1) e chama answerQuestion (pergunta) ou sendPostSaleMessage (mensagem).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","tipo","texto"],"properties":{"account_id":{"type":"string","format":"uuid"},"tipo":{"type":"string","enum":["pergunta","mensagem"]},"texto":{"type":"string","minLength":1},"external":{"type":"object","additionalProperties":true,"properties":{"question_id":{"type":["string","number"]},"pack_id":{"type":["string","number"]},"seller_id":{"type":["string","number"]},"buyer_id":{"type":["string","number"]}}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true,"description":"Chave interna service-to-service."}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"tipo":{"type":"string"},"texto_enviado":{"type":"string"},"msg_id":{"type":"string","nullable":true}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/internal/notificacoes/push/conversa":{"post":{"summary":"Push de mensagem recebida (service-to-service)","tags":["Notificações (interno)"],"description":"Rota interna Connect → core. Autentica via x-internal-key. Envia Web Push aos dispositivos inscritos em `conversa:<canal>`; se a conversa tem atendente, só aos dispositivos dele.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","conversa_id"],"properties":{"account_id":{"type":"string","format":"uuid"},"conversa_id":{"type":"string","format":"uuid"},"texto":{"type":["string","null"]},"tipo":{"type":["string","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"enviados":{"type":"number"}}}}}}}}},"/loja/{subdomain}/busca":{"get":{"summary":"Buscar produtos na loja","tags":["Busca Inteligente"],"description":"Busca do modal. Loja com busca_motor = typesense usa o motor único (Typesense com reserva Postgres) e sugere até 5 termos populares da loja que começam com o digitado (type termo). Loja no clássico usa produtos_busca_rank: exige todas as palavras, tolera erro de digitação palavra a palavra e põe SKU/GTIN exato no topo. Aplica a política de vitrine da loja (canal Loja, esgotado, sem foto), o mesmo recorte da página de resultados. Inclui você quis dizer (busca_voce_quis_dizer), sugestões de marca/categoria e redirecionar (a página do redirecionamento cadastrado para o termo, ou null). Sinônimos da loja valem nos dois motores. Não grava evento: o modal grava no Enter e no clique pelo /busca/track. Rota pública (storefront).","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Termo de busca (mín 2 caracteres)"},{"schema":{"type":"integer","default":12,"minimum":1,"maximum":24},"in":"query","name":"limit","required":false,"description":"Máximo de resultados"},{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"totalCount":{"type":"integer"},"products":{"type":"array","items":{"type":"object","additionalProperties":true}},"suggestions":{"type":"array","items":{"type":"object","additionalProperties":true}},"didYouMean":{"type":["null","string"]},"redirecionar":{"type":["null","string"]}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/loja/{subdomain}/busca/redirecionamento":{"get":{"summary":"Redirecionamento de busca da loja","tags":["Busca Inteligente"],"description":"Devolve a página para onde o termo leva, cadastrada em Loja virtual > Busca > Redirecionamentos (exato ganha de contém; entre dois contém, o termo mais longo), ou null. Não roda a busca nem grava evento. Caminho da loja (começa com uma barra só) ou endereço https. Rota pública (storefront).","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Termo buscado"},{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirecionar":{"type":["null","string"]}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/loja/{subdomain}/busca/zero-state":{"get":{"summary":"Estado inicial da busca (zero-state)","tags":["Busca Inteligente"],"description":"Retorna dados para exibir antes do usuário digitar: buscas populares (30 dias), top categorias com imagem, e lançamentos recentes. Rota pública (storefront).","parameters":[{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"popular":{"type":"array","items":{"type":"string"},"description":"Top 6 buscas populares"},"categorias":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Top 6 categorias com mais produtos"},"lancamentos":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"4 produtos mais recentes"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/loja/{subdomain}/busca/track":{"post":{"summary":"Rastrear evento de busca","tags":["Busca Inteligente"],"description":"Grava em busca_eventos (fire-and-forget): busca confirmada (Enter no modal) ou clique num resultado (modal ou página, com a posição). O clique aceita o id ou o slug do produto, resolvido dentro da loja do subdomínio. Busca gravada aqui é sempre origem modal e não entra nos termos populares (só a página gravada pelo /busca/pagina entra). Rota pública (storefront).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"Termo buscado"},"resultados_count":{"type":"integer","description":"Quantidade de resultados"},"clicked_produto_id":{"type":["string","null"],"description":"ID do produto clicado"},"clicked_produto_slug":{"type":["string","null"],"description":"Slug do produto clicado (o card da página só conhece o link)"},"posicao":{"type":["integer","null"],"minimum":0,"description":"Posição do card clicado, a partir de 1"},"origem":{"type":"string","enum":["modal","pagina"],"description":"De onde veio o evento (padrão: modal)"},"session_id":{"type":["string","null"],"description":"ID da sessão do visitante"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"204":{"description":"Evento registrado"}}}},"/loja/{subdomain}/busca/pagina":{"get":{"summary":"Página de resultados da busca (motor único)","tags":["Busca Inteligente"],"description":"Página de resultados da loja no motor único (Typesense com reserva Postgres, conforme lojas.busca_motor). A loja vem do subdomínio; nada do pedido troca o tenant. Facetas disjuntivas contadas sobre o resultado. Com registrar = true e página 1, grava a busca em busca_eventos (origem pagina). Loja no motor clássico (busca_motor = postgres) recebe 409 motor_classico sem rodar a busca. Rota pública (storefront).","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"integer","minimum":1},"in":"query","name":"pagina","required":false},{"schema":{"type":"integer","minimum":1,"maximum":250},"in":"query","name":"por_pagina","required":false},{"schema":{"type":"string"},"in":"query","name":"ordem","required":false},{"schema":{"type":"array","items":{"type":"string"}},"in":"query","name":"marca","required":false},{"schema":{"type":"array","items":{"type":"string"}},"in":"query","name":"categoria","required":false},{"schema":{"type":"integer"},"in":"query","name":"preco_min","required":false},{"schema":{"type":"integer"},"in":"query","name":"preco_max","required":false},{"schema":{"type":"boolean"},"in":"query","name":"estoque","required":false},{"schema":{"type":"boolean"},"in":"query","name":"registrar","required":false},{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}},"total":{"type":"integer"},"facetas":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"valores":{"type":"array","items":{"type":"object","properties":{"valor":{"type":"string"},"total":{"type":"number"}}}}}}},"motor":{"type":"string"},"ms":{"type":"number"},"didYouMean":{"type":["null","string"]},"populares":{"type":"array","items":{"type":"string"}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"post":{"summary":"Página de resultados da busca (motor único, com recorte B2B)","tags":["Busca Inteligente"],"description":"Página de resultados da loja no motor único (Typesense com reserva Postgres, conforme lojas.busca_motor). A loja vem do subdomínio; nada do pedido troca o tenant. Facetas disjuntivas contadas sobre o resultado. Com registrar = true e página 1, grava a busca em busca_eventos (origem pagina). Loja no motor clássico (busca_motor = postgres) recebe 409 motor_classico sem rodar a busca. Rota pública (storefront).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"q":{"type":"string"},"pagina":{"type":"integer","minimum":1},"porPagina":{"type":"integer","minimum":1,"maximum":250},"ordem":{"type":"string"},"marcas":{"type":"array","items":{"type":"string"}},"categoriaIds":{"type":"array","items":{"type":"string"}},"precoMin":{"type":["integer","null"]},"precoMax":{"type":["integer","null"]},"emEstoque":{"type":"boolean"},"atributos":{"type":"object","additionalProperties":{"type":"array","items":{"type":"string"}}},"idsPermitidos":{"type":"array","items":{"type":"string"},"description":"Catálogo B2B da unidade: só estreita, sempre dentro da loja"},"registrar":{"type":"boolean"},"janela":{"type":"boolean","description":"Ids da busca inteira (até 1.000, na ordem do motor) no lugar da página, para a loja juntar os tamanhos do mesmo modelo; pagina e porPagina são ignorados"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true,"description":"Subdomínio da loja"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ids":{"type":"array","items":{"type":"string"}},"total":{"type":"integer"},"facetas":{"type":"array","items":{"type":"object","properties":{"campo":{"type":"string"},"valores":{"type":"array","items":{"type":"object","properties":{"valor":{"type":"string"},"total":{"type":"number"}}}}}}},"motor":{"type":"string"},"ms":{"type":"number"},"didYouMean":{"type":["null","string"]},"populares":{"type":"array","items":{"type":"string"}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/status":{"get":{"summary":"Status da busca da loja","tags":["Busca Inteligente"],"description":"Saúde da busca da loja do usuário: produtos no banco e no índice (Typesense), fila de sincronização, última edição que chegou ao índice, produtos que falharam ao entrar e o motor da loja (lojas.busca_motor). `pode_trocar_motor` é true só para SUPER_ADMIN. Typesense fora do ar devolve produtos_na_busca e ultimo_envio_em nulos.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"motor":{"type":"string","enum":["postgres","typesense"]},"pode_trocar_motor":{"type":"boolean"},"indice":{"type":"object","properties":{"configurado":{"type":"boolean"},"no_ar":{"type":"boolean"}}},"produtos_no_banco":{"type":"integer"},"produtos_na_busca":{"type":["null","integer"]},"fila":{"type":"integer"},"ultimo_envio_em":{"type":["null","string"]},"erros_total":{"type":"integer"},"erros":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"nome":{"type":["null","string"]},"sku":{"type":["null","string"]},"tentativas":{"type":"integer"},"desde":{"type":["null","string"]}}}}}}}}}}}},"/busca/reindexar":{"post":{"summary":"Reindexar a busca da loja","tags":["Busca Inteligente"],"description":"Coloca todos os produtos da loja do usuário na fila de sincronização do índice (busca_enfileirar_loja) e regrava o conjunto de sinônimos da loja no índice. O worker envia em lotes a cada 5 s. Exige gestor ou dono.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"enfileirados":{"type":"integer"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/reenviar":{"post":{"summary":"Reenviar produtos ao índice da busca","tags":["Busca Inteligente"],"description":"Coloca os produtos informados de volta na fila de sincronização. Id de produto de outra loja é ignorado. Até 100 por vez. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_ids"],"additionalProperties":false,"properties":{"produto_ids":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"enfileirados":{"type":"integer"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/motor":{"put":{"summary":"Trocar o motor da busca da loja","tags":["Busca Inteligente"],"description":"Grava lojas.busca_motor da loja em que o usuário está: typesense (novo) ou postgres (clássico). Só SUPER_ADMIN nesta fatia. O novo só liga com a loja inteira no índice: com produto da loja na fila responde 409 (indice_em_preparo, com os pendentes); com o índice sem a loja, põe a loja na fila e responde 409; com o índice fora do ar, 503. A loja passa a usar o motor novo em até 15 s (cache da configuração da busca).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motor"],"additionalProperties":false,"properties":{"motor":{"type":"string","enum":["postgres","typesense"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"motor":{"type":"string","enum":["postgres","typesense"]},"enfileirados":{"type":"integer"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"},"pendentes":{"type":"integer"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/sinonimos":{"get":{"summary":"Sinônimos da busca da loja","tags":["Busca Inteligente"],"description":"Todos os sinônimos da loja do usuário, ativos e desativados, com os termos como foram digitados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sinonimos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string","enum":["mao_dupla","mao_unica"]},"termo":{"type":["null","string"]},"termos":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean"},"origem":{"type":"string","enum":["manual","planilha","sugestao"]},"atualizado_em":{"type":"string"}}}}}}}}}}},"post":{"summary":"Criar sinônimo","tags":["Busca Inteligente"],"description":"Mão dupla (termos: o grupo, 2 ou mais) ou mão única (termo: o que o cliente digita; termos: o que a busca também traz). Vale na próxima busca, nos dois motores. Termo que já está em outro sinônimo ativo volta em conflitos e não impede de salvar. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"tipo":{"type":"string","enum":["mao_dupla","mao_unica"]},"termo":{"type":["string","null"],"maxLength":200},"termos":{"type":"array","maxItems":40,"items":{"type":"string","maxLength":200}},"ativo":{"type":"boolean"},"origem":{"type":"string","enum":["manual","sugestao"]}},"required":["tipo","termos"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sinonimo":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string","enum":["mao_dupla","mao_unica"]},"termo":{"type":["null","string"]},"termos":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean"},"origem":{"type":"string","enum":["manual","planilha","sugestao"]},"atualizado_em":{"type":"string"}}},"conflitos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"termo":{"type":"string"}}}},"publicado":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/sinonimos/{id}":{"put":{"summary":"Alterar sinônimo","tags":["Busca Inteligente"],"description":"Altera tipo, termos ou ativo. O que não vier fica como está. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"tipo":{"type":"string","enum":["mao_dupla","mao_unica"]},"termo":{"type":["string","null"],"maxLength":200},"termos":{"type":"array","maxItems":40,"items":{"type":"string","maxLength":200}},"ativo":{"type":"boolean"},"origem":{"type":"string","enum":["manual","sugestao"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sinonimo":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string","enum":["mao_dupla","mao_unica"]},"termo":{"type":["null","string"]},"termos":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean"},"origem":{"type":"string","enum":["manual","planilha","sugestao"]},"atualizado_em":{"type":"string"}}},"conflitos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"termo":{"type":"string"}}}},"publicado":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir sinônimo","tags":["Busca Inteligente"],"description":"Exclui o sinônimo da loja. Deixa de valer na próxima busca. Exige gestor ou dono.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/sinonimos/importar":{"post":{"summary":"Importar sinônimos por planilha","tags":["Busca Inteligente"],"description":"CSV com ponto e vírgula, até 20 KB: uma linha por sinônimo, \"mao_dupla;bike,bicicleta\" ou \"mao_unica;tênis>tênis de corrida,sapatilha\". Com aplicar = false só confere e devolve cada linha com o erro dela; com aplicar = true grava as linhas válidas (origem planilha) e devolve quantas entraram. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["csv"],"additionalProperties":false,"properties":{"csv":{"type":"string","maxLength":40000},"aplicar":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"linhas":{"type":"array","items":{"type":"object","properties":{"linha":{"type":"integer"},"ok":{"type":"boolean"},"erro":{"type":"string"},"tipo":{"type":"string"},"termo":{"type":["null","string"]},"termos":{"type":"array","items":{"type":"string"}}}}},"validas":{"type":"integer"},"importadas":{"type":"integer"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/redirecionamentos":{"get":{"summary":"Redirecionamentos da busca da loja","tags":["Busca Inteligente"],"description":"Todos os redirecionamentos de termo da loja do usuário, ativos e desativados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirecionamentos":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"termo":{"type":"string"},"correspondencia":{"type":"string","enum":["exato","contem"]},"url":{"type":"string"},"ativo":{"type":"boolean"},"atualizado_em":{"type":"string"}}}}}}}}}}},"post":{"summary":"Criar redirecionamento de busca","tags":["Busca Inteligente"],"description":"Termo que leva a uma página: exato (a busca inteira é o termo) ou contém (o termo aparece em palavras inteiras). Destino: caminho da loja (começa com uma barra só) ou https. 422 url_invalida; 409 redirecionamento_duplicado. Vale na próxima busca, só na loja. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"termo":{"type":"string","maxLength":200},"correspondencia":{"type":"string","enum":["exato","contem"]},"url":{"type":"string","maxLength":2000},"ativo":{"type":"boolean"}},"required":["termo","correspondencia","url"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirecionamento":{"type":"object","properties":{"id":{"type":"string"},"termo":{"type":"string"},"correspondencia":{"type":"string","enum":["exato","contem"]},"url":{"type":"string"},"ativo":{"type":"boolean"},"atualizado_em":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/redirecionamentos/{id}":{"put":{"summary":"Alterar redirecionamento de busca","tags":["Busca Inteligente"],"description":"Altera termo, correspondência, destino ou ativo. O que não vier fica como está. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"termo":{"type":"string","maxLength":200},"correspondencia":{"type":"string","enum":["exato","contem"]},"url":{"type":"string","maxLength":2000},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"redirecionamento":{"type":"object","properties":{"id":{"type":"string"},"termo":{"type":"string"},"correspondencia":{"type":"string","enum":["exato","contem"]},"url":{"type":"string"},"ativo":{"type":"boolean"},"atualizado_em":{"type":"string"}}}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir redirecionamento de busca","tags":["Busca Inteligente"],"description":"Exclui o redirecionamento da loja. Exige gestor ou dono.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/sugestoes":{"get":{"summary":"Sugestões de sinônimo e redirecionamento","tags":["Busca Inteligente"],"description":"Tiradas das buscas dos últimos 30 dias, sem IA (busca_sugestoes, migration 467): reformulacao (busca sem resultado seguida, na mesma visita, de uma com resultado) e sem_resultado (2 buscas ou mais sem resultado). Some o que já tem sinônimo ou redirecionamento e o que foi dispensado.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sugestoes":{"type":"array","items":{"type":"object","properties":{"tipo":{"type":"string","enum":["reformulacao","sem_resultado"]},"termo":{"type":"string"},"alternativa":{"type":["null","string"]},"buscas":{"type":"integer"},"ultima_em":{"type":"string"}}}}}}}}}}}},"/busca/sugestoes/dispensar":{"post":{"summary":"Dispensar sugestão da busca","tags":["Busca Inteligente"],"description":"A sugestão (termo e alternativa) não volta para a lista da loja. Exige gestor ou dono.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["termo"],"additionalProperties":false,"properties":{"termo":{"type":"string","minLength":1,"maxLength":200},"alternativa":{"type":["string","null"],"maxLength":200}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/busca/produtos":{"get":{"summary":"Buscar produtos no motor único","tags":["Busca Inteligente"],"description":"Busca de produto no motor da loja (Typesense com reserva Postgres, conforme lojas.busca_motor), na ordem de relevância. Usuário do painel: a loja é a dele. Serviço interno: header x-internal-key e a loja em account_id. contexto=admin (padrão) acha qualquer status; contexto=loja devolve só o que a vitrine mostra, com a política da loja (esgotado e sem foto).","parameters":[{"schema":{"type":"string","maxLength":200},"in":"query","name":"q","required":false,"description":"O que buscar"},{"schema":{"type":"integer","minimum":1,"default":8},"in":"query","name":"limite","required":false,"description":"Até 50"},{"schema":{"type":"string","enum":["admin","loja"],"default":"admin"},"in":"query","name":"contexto","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false,"description":"Só na chamada interna"}],"security":[{"bearerAuth":[]},{"internalKey":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":["null","string"]},"sku":{"type":["null","string"]},"marca":{"type":["null","string"]},"categoria":{"type":["null","string"]},"preco":{"type":["null","integer"],"description":"Centavos"},"preco_promocional":{"type":["null","integer"],"description":"Centavos"},"estoque":{"type":["null","number"]},"unidade":{"type":["null","string"]},"descricao":{"type":["null","string"],"description":"Até 500 caracteres"},"slug":{"type":["null","string"]},"imagem":{"type":["null","string"],"description":"Capa, ou a primeira imagem"},"status_produto":{"type":["null","string"]},"ativo":{"type":["null","boolean"]},"disponivel":{"type":"boolean","description":"Tem estoque publicável (disponivel_vitrine)"}}}},"total":{"type":"integer","description":"Todos que casam, não só os devolvidos"},"motor":{"type":"string","enum":["typesense","postgres"]},"ms":{"type":"number"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/apps":{"get":{"summary":"Listar apps instalados","tags":["Apps - Registro"],"description":"Retorna todos os apps instalados no tenant, ordenados por data de instalação.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/apps/{appId}":{"get":{"summary":"Detalhe de app instalado","tags":["Apps - Registro"],"description":"Retorna dados completos de um app instalado no tenant.","parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar configuração do app","tags":["Apps - Registro"],"description":"Atualiza config_global ou status ativo/inativo. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"},"configGlobal":{"type":"object","additionalProperties":true}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desinstalar app","tags":["Apps - Registro"],"description":"Remove o app do tenant (hard delete do registro). Requer role owner/manager.","parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/apps/{appId}/install":{"post":{"summary":"Instalar ou reativar app","tags":["Apps - Registro"],"description":"Instala um app no tenant via upsert. Requer role owner/manager. Se já instalado, reativa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"versao":{"type":"string"},"configGlobal":{"type":"object","additionalProperties":true}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/apps/{appId}/conteudo":{"get":{"summary":"Listar conteúdo do app","tags":["Apps - Conteúdo"],"description":"Retorna registros de conteúdo do app, ordenados por ordem. Aceita filtro opcional por chave.","parameters":[{"schema":{"type":"string"},"in":"query","name":"chave","required":false,"description":"Filtro por chave do conteúdo"},{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar registro de conteúdo","tags":["Apps - Conteúdo"],"description":"Cria um novo registro de conteúdo para o app. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["chave"],"properties":{"chave":{"type":"string"},"valor":{"type":"object","additionalProperties":true},"ordem":{"type":"integer","default":0}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/apps/{appId}/conteudo/{id}":{"patch":{"summary":"Atualizar conteúdo","tags":["Apps - Conteúdo"],"description":"Atualiza valor e/ou ordem de um registro de conteúdo. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"valor":{"type":"object","additionalProperties":true},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover registro de conteúdo","tags":["Apps - Conteúdo"],"description":"Remove um registro de conteúdo do app. Requer role owner/manager.","parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/apps/{appId}/conteudo/reordenar":{"post":{"summary":"Reordenar registros de conteúdo","tags":["Apps - Conteúdo"],"description":"Reordena registros de conteúdo pelo array de IDs. A posição no array define a ordem. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/apps/{appId}/eventos":{"get":{"summary":"Listar eventos do app","tags":["Apps - Eventos"],"description":"Retorna eventos do app com filtros por período, tipo e limite. Máx 1000 registros.","parameters":[{"schema":{"type":"string","format":"date-time"},"in":"query","name":"desde","required":false,"description":"Data início (ISO)"},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"ate","required":false,"description":"Data fim (ISO)"},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false,"description":"Filtro por tipo de evento"},{"schema":{"type":"integer","default":100,"maximum":1000},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/apps/{appId}/eventos/agregado":{"get":{"summary":"Eventos agregados do app","tags":["Apps - Eventos"],"description":"Agrega eventos por dia, tipo ou produto_id com métrica count ou sum_valor. Lê o período inteiro paginando; acima de 50 mil eventos a resposta é parcial e marca o header x-metricas-parciais.","parameters":[{"schema":{"type":"string","enum":["count","sum_valor"],"default":"count"},"in":"query","name":"metric","required":false},{"schema":{"type":"string","enum":["dia","tipo","produto_id"],"default":"dia"},"in":"query","name":"group_by","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"desde","required":false},{"schema":{"type":"string","format":"date-time"},"in":"query","name":"ate","required":false},{"schema":{"type":"string"},"in":"query","name":"filtro_tipo","required":false},{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"chave":{"type":"string"},"valor":{"type":"number"}}}}}}}}}},"/apps/{appId}/conversao":{"get":{"summary":"Métricas de conversão do app","tags":["Apps - Eventos"],"description":"Retorna cliques, compras atribuídas, GMV e ticket médio. Usa RPC get_app_conversao. Default: últimos 30 dias.","parameters":[{"schema":{"type":"string","format":"date-time"},"in":"query","name":"desde","required":false,"description":"Data início (default: 30 dias atrás)"},{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cliques":{"type":"integer"},"compras_atribuidas":{"type":"integer"},"gmv_centavos":{"type":"integer"},"ticket_medio_centavos":{"type":"number"}}}}}}}}},"/public/apps/{appId}/eventos":{"post":{"summary":"Registrar evento do app (público)","tags":["Apps - Eventos (Público)"],"description":"Registra evento do app a partir do storefront. Resolve tenant por subdomain, valida app ativo, aplica whitelist de tipo e sanitização. Idempotente por event_id (UNIQUE). Rate limit: 60/min por IP+visitante. Cap: 1000 eventos/sessão/24h.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain","event_id","tipo"],"properties":{"subdomain":{"type":"string","description":"Subdomínio da loja"},"event_id":{"type":"string","description":"ID único do evento (idempotência)"},"tipo":{"type":"string","description":"Tipo do evento (whitelist por app)"},"dados":{"type":"object","additionalProperties":true},"produto_id":{"type":"string","format":"uuid"},"valor_centavos":{"type":"integer"},"visitante_id":{"type":"string"},"sessao_id":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"appId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/reel-colecoes":{"get":{"summary":"Listar coleções de reels","tags":["Conteúdo - Reels"],"description":"Retorna coleções do tenant com contagem de reels. Filtro por ativa.","parameters":[{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativa","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar coleção","tags":["Conteúdo - Reels"],"description":"Cria coleção de reels com slug gerado automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"capa_url":{"type":"string"},"ordem":{"type":"integer"},"ativa":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/reel-colecoes/{id}":{"patch":{"summary":"Atualizar coleção","tags":["Conteúdo - Reels"],"description":"Atualiza nome, capa, ordem ou status da coleção.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir coleção","tags":["Conteúdo - Reels"],"description":"Remove coleção de reels.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reel-colecoes/reordenar":{"post":{"summary":"Reordenar coleções","tags":["Conteúdo - Reels"],"description":"Define nova ordem das coleções via array de IDs.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels/quota":{"get":{"summary":"Quota de reels","tags":["Conteúdo - Reels"],"description":"Retorna uso atual e limites do plano (reels, bytes, imports).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels":{"get":{"summary":"Listar reels","tags":["Conteúdo - Reels"],"description":"Lista reels do tenant com paginação e filtros por status e coleção.","parameters":[{"schema":{"type":"integer"},"in":"query","name":"page","required":false},{"schema":{"type":"integer"},"in":"query","name":"page_size","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"colecao_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels/upload-url":{"post":{"summary":"Gerar URL de upload","tags":["Conteúdo - Reels"],"description":"Gera signed upload URL para vídeo e thumbnail. Valida quota do plano, MIME e tamanho.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["filename","mime"],"properties":{"filename":{"type":"string"},"bytes":{"type":"integer"},"mime":{"type":"string"},"titulo":{"type":"string"},"colecao_id":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/reels/{id}/finalizar":{"post":{"summary":"Finalizar upload do reel","tags":["Conteúdo - Reels"],"description":"Confirma upload do vídeo no storage e atualiza paths. Gera URLs assinadas de leitura.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"duracao_s":{"type":"number"},"titulo":{"type":"string"},"descricao":{"type":"string"},"colecao_id":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels/importar":{"post":{"summary":"Importar reel de rede social","tags":["Conteúdo - Reels"],"description":"Importa vídeo do TikTok ou Instagram via Apify. Processamento em background (202 Accepted).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string"},"colecao_id":{"type":"string"},"titulo":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reel_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/reels/{id}/retry":{"post":{"summary":"Re-tentar importação de reel","tags":["Conteúdo - Reels"],"description":"Re-dispara a importação de um reel que falhou (status=erro), reusando a URL de origem. Processamento em background (202).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"reel_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/reels/{id}":{"get":{"summary":"Detalhe do reel","tags":["Conteúdo - Reels"],"description":"Retorna reel com produtos vinculados e URLs assinadas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar reel","tags":["Conteúdo - Reels"],"description":"Atualiza título, descrição, coleção, status ou ordem do reel.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"titulo":{"type":"string"},"descricao":{"type":"string"},"colecao_id":{"type":["string","null"]},"status":{"type":"string","enum":["rascunho","publicado","arquivado"]},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir reel","tags":["Conteúdo - Reels"],"description":"Remove reel e limpa arquivos do storage (async).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels/{id}/analytics":{"get":{"summary":"Analytics do reel","tags":["Conteúdo - Reels"],"description":"Métricas do reel: views, play complete, ATC, shares, pedidos atribuídos e receita.","parameters":[{"schema":{"type":"integer","default":30},"in":"query","name":"dias","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/reels/{id}/produtos":{"get":{"summary":"Produtos do reel","tags":["Conteúdo - Reels"],"description":"Lista produtos vinculados ao reel ordenados por posição.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Definir produtos do reel","tags":["Conteúdo - Reels"],"description":"Substitui todos os produtos do reel (replace strategy).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produtos"],"properties":{"produtos":{"type":"array","items":{"type":"object","properties":{"produto_id":{"type":"string"},"ordem":{"type":"integer"},"desconto_override":{"type":"number"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{subdomain}/reels/colecoes":{"get":{"summary":"Coleções públicas da loja","tags":["Conteúdo - Reels"],"description":"Retorna coleções ativas com preview (storefront público).","parameters":[{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{subdomain}/reels":{"get":{"summary":"Reels públicos da loja","tags":["Conteúdo - Reels"],"description":"Lista reels publicados com produtos e imagens (storefront público). Filtros por coleção, produto e categoria.","parameters":[{"schema":{"type":"string"},"in":"query","name":"colecao_id","required":false},{"schema":{"type":"string"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string"},"in":"query","name":"categoria_id","required":false},{"schema":{"type":"integer","default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{subdomain}/reels/{id}/view":{"post":{"summary":"Registrar view de reel","tags":["Conteúdo - Reels"],"description":"Fire-and-forget: registra evento reel_view no tracking (storefront público).","parameters":[{"schema":{"type":"string"},"in":"path","name":"subdomain","required":true},{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/live-colecoes":{"get":{"summary":"Listar coleções de lives","tags":["Conteúdo - Lives"],"description":"Retorna coleções de lives do tenant.","parameters":[{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativa","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar coleção de lives","tags":["Conteúdo - Lives"],"description":"Cria coleção de lives com slug informado (único por tenant).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","slug"],"properties":{"nome":{"type":"string"},"slug":{"type":"string"},"capa_url":{"type":"string"},"ordem":{"type":"integer"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/lives":{"get":{"summary":"Listar lives","tags":["Conteúdo - Lives"],"description":"Lista lives do tenant. Filtros opcionais por status e coleção.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"colecao_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar live","tags":["Conteúdo - Lives"],"description":"Cria uma live em status rascunho. Slug destaque é reservado (422 slug_reservado); cupom_codigo precisa ser cupom ativo do tenant (422 cupom_invalido).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["titulo","slug"],"additionalProperties":true}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/lives/{id}":{"get":{"summary":"Detalhe da live","tags":["Conteúdo - Lives"],"description":"Retorna a live com produtos vinculados (ordenados), cada produto com imagem_url (capa ou primeira imagem).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar live","tags":["Conteúdo - Lives"],"description":"Atualiza campos editáveis da live (não altera slug nem status). cupom_codigo precisa ser cupom ativo do tenant (422 cupom_invalido), conferido só quando muda; youtube_video_id, scheduled_at, descricao e host_nome aceitam null para limpar; limpar scheduled_at de live agendada dá 422 data_obrigatoria_para_agendada. Corpo inválido: 400 dados_invalidos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir live","tags":["Conteúdo - Lives"],"description":"Remove a live e seus vínculos (cascade).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/lives/{id}/produtos":{"put":{"summary":"Definir produtos da live","tags":["Conteúdo - Lives"],"description":"Substitui todos os produtos vinculados à live (replace strategy).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produtos"],"additionalProperties":true}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/lives/{id}/marcadores":{"get":{"summary":"Marcadores da live","tags":["Conteúdo - Lives"],"description":"Trilha de produtos no tempo da live, ordenada por inicio_s e posicao.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"put":{"summary":"Definir marcadores da live","tags":["Conteúdo - Lives"],"description":"Substitui a trilha de marcadores (replace, máx. 200). Produto precisa ser do tenant (422 produto_invalido); fim_s > inicio_s e sem o mesmo produto repetido no mesmo segundo (422 marcador_invalido). Devolve a lista gravada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["marcadores"],"additionalProperties":true}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/lives/{id}/status":{"post":{"summary":"Transicionar status da live","tags":["Conteúdo - Lives"],"description":"Aplica uma transição de status validada pela máquina de estados. Seta started_at/ended_at conforme o destino. Encerrar live do YouTube com vídeo marca replay_pronto; ir para replay exige replay_pronto (422 reprise_indisponivel).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/loja/{sub}/lives":{"get":{"summary":"Lives públicas da loja","tags":["Conteúdo - Lives"],"description":"Lista lives em agenda/ao-vivo/replay pronta (storefront público). cupom_codigo sai null se o checkout não aceita mais o cupom. Nunca expõe stream_key/ingest.","parameters":[{"schema":{"type":"string"},"in":"query","name":"colecao_id","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"integer","default":30},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{sub}/lives/destaque":{"get":{"summary":"Live de destaque da loja","tags":["Conteúdo - Lives"],"description":"A live que a loja deve mostrar agora, no formato do detalhe, ou null. Prioridade: ao_vivo mais recente; senão a próxima agendada com scheduled_at >= agora - 60 min (atrasada continua destaque por 60 min); senão a reprise pronta mais recente. Nunca expõe stream_key/ingest.","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{sub}/lives/{slug}":{"get":{"summary":"Detalhe público da live","tags":["Conteúdo - Lives"],"description":"Retorna a live pública por slug com produtos visíveis na vitrine (ativos e com disponivel_b2c não falso; ordenados, com imagem), marcadores e cupom_codigo só se o checkout ainda o aceita. Reprise só com replay_pronto. Nunca expõe stream_key/ingest nem desconto_override.","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/loja/{sub}/lives/{slug}/chat":{"get":{"summary":"Chat público da live","tags":["Conteúdo - Lives"],"description":"Mensagens visíveis do chat da live (nunca as bloqueadas) e quantas pessoas assistem agora. Ao vivo: as últimas 60, em ordem de envio. Reprise: todas (até 2.000), para a loja reapresentar cada uma no segundo em que foi feita (criado_em menos started_at). Agendada: lista vazia. Resposta com cache de 1,5 s. Limite próprio de 120 leituras por minuto por IP.","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Enviar mensagem no chat da live","tags":["Conteúdo - Lives"],"description":"Manda uma mensagem no chat de uma live vertical (9:16) ao vivo. Vale o `nome` digitado (2 a 40 letras, sem link e sem se passar pela loja). Cliente logado (Authorization) que não mandou `nome` aparece com o primeiro nome do cadastro, ou \"Cliente\"; o vínculo com o cliente fica gravado e não sai na rota pública. Texto até 200 caracteres, sem link. Limite por sessão (1 a cada 2 s, 8 por minuto) e por IP (30 por minuto): 429 muitas_mensagens com tentar_em_s. Erros 422: chat_indisponivel (live 16:9, que não tem chat), chat_fechado, nome_obrigatorio, nome_invalido, mensagem_vazia, mensagem_longa, mensagem_com_link; 400 sessao_invalida.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"texto":{"type":"string"},"nome":{"type":"string"},"sessao":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/loja/{sub}/lives/{slug}/presenca":{"post":{"summary":"Presença na live","tags":["Conteúdo - Lives"],"description":"Heartbeat da aba que assiste a live (a cada ~20 s). Conta as sessões vistas nos últimos 45 s, no máximo 5 por IP por live. Ao vivo, atualiza lives.viewers_pico quando a contagem passa do pico. Agendada devolve 0. Limite próprio de 60 batidas por minuto por IP.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"sessao":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/lives/{id}/mensagens":{"get":{"summary":"Mensagens do chat da live","tags":["Conteúdo - Lives"],"description":"Últimas 200 mensagens do chat da live, mais novas primeiro, incluindo as bloqueadas (moderação).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/lives/{id}/mensagens/{mensagemId}":{"patch":{"summary":"Bloquear ou liberar mensagem do chat","tags":["Conteúdo - Lives"],"description":"Bloqueada some do chat da loja em até cerca de 6 s (1,5 s de cache no core, 2 s de cache no web e 2,5 s entre leituras do player) e da reprise.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["bloqueada"],"additionalProperties":true,"properties":{"bloqueada":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"mensagemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Apagar mensagem do chat","tags":["Conteúdo - Lives"],"description":"Remove a mensagem do chat da live de vez.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"mensagemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cart":{"get":{"summary":"Hidratar carrinho da loja virtual","tags":["Checkout - Cart (Server-side)"],"description":"Lê o pedido rascunho ativo da sessão da loja (Shopify Cart pattern). NÃO cria — sessão sem carrinho responde `id: null` e `items: []`; a linha em `pedidos` só nasce no primeiro item adicionado. Retorna itens, cupom, frete, promoções automáticas, cliente e endereços vinculados (Send Invoice pre-fill). Aceita `b2b_unidade_id` (vazio = varejo) para sincronizar o modo atacado do rascunho. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string"},"in":"query","name":"session_token","required":true},{"schema":{"type":"string"},"in":"query","name":"b2b_unidade_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","nullable":true},"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"subtotalCentavos":{"type":"integer"},"cupomId":{"type":"string","nullable":true},"cupom":{"type":"object","nullable":true,"additionalProperties":true},"descontoCentavos":{"type":"integer"},"promocoesAutomaticas":{"type":"array","items":{"type":"object","additionalProperties":true}},"freteOpcao":{"type":"object","nullable":true,"additionalProperties":true},"cepFrete":{"type":"string","nullable":true},"giftWrapCentavos":{"type":"integer"},"giftWrapPrecoUnitarioCentavos":{"type":"integer"},"giftWrapDisponivel":{"type":"boolean"},"b2bUnidadeId":{"type":"string","nullable":true},"b2bItensForaCatalogo":{"type":"array","items":{"type":"object","additionalProperties":true}},"cliente":{"type":"object","nullable":true,"additionalProperties":true},"enderecos":{"type":"array","items":{"type":"object","additionalProperties":true}},"checkoutDados":{"type":"object","nullable":true,"properties":{"email":{"type":"string","nullable":true},"telefone":{"type":"string","nullable":true},"nome":{"type":"string","nullable":true},"documento":{"type":"string","nullable":true,"description":"Só o CNPJ (14 dígitos). O CPF gravado no rascunho NUNCA é devolvido: o session_token viaja no link de recuperação, que é encaminhável. O comprador redigita o CPF."},"razao_social":{"type":"string","nullable":true},"ie":{"type":"string","nullable":true},"cep":{"type":"string","nullable":true},"logradouro":{"type":"string","nullable":true},"numero":{"type":"string","nullable":true},"complemento":{"type":"string","nullable":true},"bairro":{"type":"string","nullable":true},"cidade":{"type":"string","nullable":true},"uf":{"type":"string","nullable":true}}}}}}}}}},"delete":{"summary":"Esvaziar carrinho (pós-checkout)","tags":["Checkout - Cart (Server-side)"],"description":"Descarta o rascunho ativo (cancelado/descartado) para que o próximo GET /cart crie um novo limpo. Usado após checkout concluído. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string"},"in":"query","name":"session_token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"success":{"type":"boolean"}}}}}}}}},"/cart/checkout":{"patch":{"summary":"Salvar dados do checkout no carrinho","tags":["Checkout - Cart (Server-side)"],"description":"Grava no pedido rascunho ATIVO da sessão os campos válidos do checkout (contato, documento, endereço). Campo vazio ou inválido é ignorado e nunca apaga o que já está salvo. NÃO cria carrinho: sessão sem rascunho ativo responde `salvo: false`. No primeiro e-mail ou telefone válido marca `checkout_iniciado_em` e emite `checkout_started`. `aceita_marketing: true` registra o consentimento de marketing e WhatsApp (origem checkout); `false` registra a revogação (`withdrawn`) de quem tinha aceitado. Só grava quando o estado muda. Endpoint público (sem JWT), limitado por IP.","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"salvo":{"type":"boolean"},"cupom_recusado":{"type":"object","properties":{"codigo":{"type":"string"},"motivo":{"type":"string"}}}}}}}}}}},"/cart/items":{"post":{"summary":"Adicionar item ao carrinho da loja","tags":["Checkout - Cart (Server-side)"],"description":"Adiciona produto ao carrinho ou incrementa quantidade se já existe (mesmo produto+variacao). Quantidade final do SKU acima do estoque vendável responde 422 `estoque_insuficiente` com `disponivel` e `no_carrinho`. Emite eventos cart_started e cart_item_added. Endpoint público (sem JWT).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"subtotalCentavos":{"type":"integer"},"giftWrapCentavos":{"type":"integer"},"giftWrapPrecoUnitarioCentavos":{"type":"integer"},"giftWrapDisponivel":{"type":"boolean"}}}}}}}}},"/cart/items/{id}":{"patch":{"summary":"Atualizar quantidade de item do carrinho","tags":["Checkout - Cart (Server-side)"],"description":"Atualiza a quantidade de um item. Se quantidade = 0, remove o item. Quantidade acima do estoque vendável vai para o máximo e a resposta traz `ajuste` (solicitado, ajustado_para, disponivel). Recalcula totais com cupom e promoções. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"subtotalCentavos":{"type":"integer"},"giftWrapCentavos":{"type":"integer"},"giftWrapPrecoUnitarioCentavos":{"type":"integer"},"giftWrapDisponivel":{"type":"boolean"}}}}}}}},"delete":{"summary":"Remover item do carrinho","tags":["Checkout - Cart (Server-side)"],"description":"Remove um item do carrinho da loja e recalcula totais. Aceita `b2b_unidade_id` (vazio = varejo) para sincronizar o modo atacado. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string"},"in":"query","name":"session_token","required":true},{"schema":{"type":"string"},"in":"query","name":"b2b_unidade_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"subtotalCentavos":{"type":"integer"},"giftWrapCentavos":{"type":"integer"},"giftWrapPrecoUnitarioCentavos":{"type":"integer"},"giftWrapDisponivel":{"type":"boolean"}}}}}}}}},"/cart/ajustar-estoque":{"post":{"summary":"Ajustar o carrinho ao estoque disponível","tags":["Checkout - Cart (Server-side)"],"description":"Remove do carrinho as linhas sem estoque e reduz as demais ao saldo vendável (mesma fonte do fechamento do pedido). Linha de kit montado ou de order bump tem quantidade travada: sem saldo para ela, sai inteira (o kit sai com todas as linhas). Responde o carrinho canônico mais `ajustes` (item_id, nome, solicitado, ajustado_para, disponivel). Endpoint público (sem JWT).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":true}},"ajustes":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/cart/coupon":{"post":{"summary":"Aplicar cupom de desconto","tags":["Checkout - Cart (Server-side)"],"description":"Valida e aplica um cupom ao carrinho. Recalcula totais incluindo promoções automáticas que respeitam acumula_com_cupom. Rate-limited: 10 req/min. Endpoint público (sem JWT).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cupom":{"type":"object","additionalProperties":true},"descontoCentavos":{"type":"integer"},"totalCentavos":{"type":"integer"},"promocoesAutomaticas":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"delete":{"summary":"Remover cupom do carrinho","tags":["Checkout - Cart (Server-side)"],"description":"Remove o cupom aplicado e recalcula totais sem desconto. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string"},"in":"query","name":"session_token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"cupomId":{"type":"string","nullable":true}}}}}}}}},"/cart/merge":{"post":{"summary":"Associar carrinho anônimo a usuário logado","tags":["Checkout - Cart (Server-side)"],"description":"Resolve cliente_id pelo auth_user_id e vincula ao rascunho. Usado após login/OTP do cliente para merge de sessão. Endpoint público (sem JWT).","responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"cartId":{"type":"string"},"clienteId":{"type":"string","nullable":true}}}}}}}}},"/locais-retirada":{"get":{"summary":"Listar pontos de retirada (admin)","tags":["Logística - Pontos de Retirada"],"description":"Retorna todos os tenant_locations do tenant logado, ordenados por \"ordem\". Endpoint de administração.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"cep":{"type":["null","string"]},"logradouro":{"type":["null","string"]},"numero":{"type":["null","string"]},"complemento":{"type":["null","string"]},"bairro":{"type":["null","string"]},"cidade":{"type":["null","string"]},"uf":{"type":["null","string"]},"ativo":{"type":"boolean"},"serve_retirada":{"type":"boolean"},"serve_estoque":{"type":"boolean"},"principal":{"type":"boolean"},"ordem":{"type":["null","integer"]}}}}}}}}},"post":{"summary":"Criar ponto de retirada","tags":["Logística - Pontos de Retirada"],"description":"Cria um novo tenant_location para retirada. Todos os campos de endereço e configuração são aceitos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"},"serve_retirada":{"type":"boolean"},"serve_estoque":{"type":"boolean"},"principal":{"type":"boolean"},"ativo":{"type":"boolean"},"prazo_preparo_horas":{"type":"integer"},"instrucoes":{"type":"string"},"ordem":{"type":"integer"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Ponto de retirada criado","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ponto de retirada criado"}}}}}}},"/public/locais-retirada/{accountId}":{"get":{"summary":"Listar pontos de retirada (público/checkout)","tags":["Logística - Pontos de Retirada"],"description":"Endpoint público (sem JWT) para o checkout. Retorna apenas locations com serve_retirada=true e ativo=true. Respeita o master switch aceita_retirada_loja da tabela lojas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"cep":{"type":["null","string"]},"logradouro":{"type":["null","string"]},"numero":{"type":["null","string"]},"complemento":{"type":["null","string"]},"bairro":{"type":["null","string"]},"cidade":{"type":["null","string"]},"uf":{"type":["null","string"]},"prazo_preparo_horas":{"type":["null","integer"]},"instrucoes":{"type":["null","string"]}}}}}}}}}},"/locais-retirada/{id}":{"patch":{"summary":"Atualizar ponto de retirada","tags":["Logística - Pontos de Retirada"],"description":"Atualiza campos de um ponto de retirada existente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"complemento":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"},"serve_retirada":{"type":"boolean"},"serve_estoque":{"type":"boolean"},"principal":{"type":"boolean"},"ativo":{"type":"boolean"},"prazo_preparo_horas":{"type":"integer"},"instrucoes":{"type":"string"},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Ponto de retirada atualizado","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Ponto de retirada atualizado"}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Remover ponto de retirada","tags":["Logística - Pontos de Retirada"],"description":"Remove permanentemente um ponto de retirada (hard delete).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removido com sucesso"}}}},"/public/agendamento/disponibilidade":{"post":{"summary":"Consultar disponibilidade de agendamento (checkout)","tags":["Agendamento - Entrega e Retirada"],"description":"Endpoint público. Retorna dias/slots disponíveis para o método (entrega_local|retirada) e itens do carrinho informados. ativo=false quando o app está desinstalado/inativo ou não há perfil configurado para o contexto — nunca 404.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","metodo","itens"],"properties":{"account_id":{"type":"string","format":"uuid"},"metodo":{"type":"string","enum":["entrega_local","retirada"]},"local_id":{"type":"string","format":"uuid"},"shipping_rule_id":{"type":"string","format":"uuid"},"itens":{"type":"array","items":{"type":"object","required":["produto_id","qtd"],"properties":{"produto_id":{"type":"string","format":"uuid"},"qtd":{"type":"integer","minimum":1}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ativo":{"type":"boolean"},"obrigatorio":{"type":"boolean"},"perfil_id":{"type":["null","string"]},"dias":{"type":"array","items":{"type":"object","additionalProperties":true}},"metodo_indisponivel":{"type":"boolean"},"produtos_conflitantes":{"type":"array","items":{"type":"string"}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]},"retry_after_s":{"type":"integer"}}}}}}}}},"/public/agendamento/reservar":{"post":{"summary":"Reservar capacidade de uma janela (carrinho)","tags":["Agendamento - Entrega e Retirada"],"description":"Endpoint público. Cria/renova uma reserva de capacidade TTL 15min para a sessão do carrinho, via RPC agendamento_reservar (idempotente por cart_session_id).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","janela_id","data","cart_session_id","qtd_itens"],"properties":{"account_id":{"type":"string","format":"uuid"},"janela_id":{"type":"string","format":"uuid"},"data":{"type":"string"},"cart_session_id":{"type":"string"},"qtd_itens":{"type":"integer"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"motivo":{"type":"string"},"reserva_expira_em":{"type":"string"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]},"retry_after_s":{"type":"integer"}}}}}}}}},"/public/agendamento/reagendar":{"post":{"summary":"Reagendar a janela de um pedido já confirmado","tags":["Agendamento - Entrega e Retirada"],"description":"Endpoint público usado pela página de acompanhamento do pedido. Autenticação por posse: pedido_token é o email usado na compra (mesmo mecanismo anti-enumeração de /public/pedidos/track). Valida antecedência mínima, reserva a nova janela, libera a antiga e confirma atomicamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","pedido_id","pedido_token","janela_id","data"],"properties":{"account_id":{"type":"string","format":"uuid"},"pedido_id":{"type":"string","format":"uuid"},"pedido_token":{"type":"string","description":"Email usado na compra — mesma prova de posse do tracking público."},"janela_id":{"type":"string","format":"uuid"},"data":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"motivo":{"type":"string"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]},"retry_after_s":{"type":"integer"}}}}}}}}},"/agendamento/perfis":{"get":{"summary":"Listar perfis de agendamento (com janelas aninhadas)","tags":["Agendamento - Admin"],"description":"Retorna todos os perfis do tenant logado, cada um com suas janelas (grade semanal). Escopado por account_id do JWT.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar perfil de agendamento","tags":["Agendamento - Admin"],"description":"Cria um perfil de agendamento (método + local/zona + regras de preparo/cutoff/horizonte). local_id para retirada; shipping_rule_id opcional para entrega_local (null = qualquer entrega local).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["metodo"],"properties":{"metodo":{"type":"string","enum":["entrega_local","retirada"]},"local_id":{"type":["string","null"],"format":"uuid"},"shipping_rule_id":{"type":["string","null"],"format":"uuid"},"preparo_minutos":{"type":"integer","minimum":0},"cutoff_hora":{"type":["string","null"]},"preparo_pos_cutoff_minutos":{"type":["integer","null"],"minimum":0},"horizonte_dias":{"type":"integer","minimum":1},"antecedencia_reagendamento_horas":{"type":"integer","minimum":0},"obrigatorio":{"type":"boolean"},"ativo":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/setup-status":{"get":{"summary":"Status de ativação (checklist do editor)","tags":["Agendamento - Admin"],"description":"Agrega pré-requisitos de retirada e entrega local + flags pronto_* (AND). Escopado por account_id do JWT.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/perfis/{id}":{"patch":{"summary":"Atualizar perfil de agendamento","tags":["Agendamento - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","description":"metodo/local_id/shipping_rule_id não são editáveis após a criação — apenas os campos abaixo.","properties":{"preparo_minutos":{"type":"integer","minimum":0},"cutoff_hora":{"type":["string","null"]},"preparo_pos_cutoff_minutos":{"type":["integer","null"],"minimum":0},"horizonte_dias":{"type":"integer","minimum":1},"antecedencia_reagendamento_horas":{"type":"integer","minimum":0},"obrigatorio":{"type":"boolean"},"ativo":{"type":"boolean"}}}}},"description":"metodo/local_id/shipping_rule_id não são editáveis após a criação — apenas os campos abaixo."},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover/desativar perfil de agendamento","tags":["Agendamento - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/perfis/{id}/janelas":{"post":{"summary":"Criar uma janela no perfil","tags":["Agendamento - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["dia_semana","hora_inicio","hora_fim"],"properties":{"dia_semana":{"type":"integer","minimum":0,"maximum":6},"hora_inicio":{"type":"string"},"hora_fim":{"type":"string"},"capacidade_pedidos":{"type":["integer","null"],"minimum":1},"capacidade_itens":{"type":["integer","null"],"minimum":1},"taxa_centavos":{"type":"integer","minimum":0},"ativo":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/perfis/{id}/janelas/lote":{"post":{"summary":"Gerar janelas em massa","tags":["Agendamento - Admin"],"description":"Fatia o intervalo [hora_inicio, hora_fim) em slots de duracao_minutos e cria N janelas por dia da semana. Sobra final menor que a duração é descartada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["dias_semana","hora_inicio","hora_fim","duracao_minutos"],"properties":{"dias_semana":{"type":"array","items":{"type":"integer","minimum":0,"maximum":6},"minItems":1},"hora_inicio":{"type":"string"},"hora_fim":{"type":"string"},"duracao_minutos":{"type":"integer","minimum":5},"capacidade_pedidos":{"type":["integer","null"],"minimum":1},"capacidade_itens":{"type":["integer","null"],"minimum":1},"taxa_centavos":{"type":"integer","minimum":0}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"criadas":{"type":"integer"},"puladas":{"type":"integer"},"slots_por_dia":{"type":"integer"},"dias":{"type":"integer"},"janelas":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/perfis/{id}/grade":{"put":{"summary":"Aplicar grade semanal (reconciliação de janelas)","tags":["Agendamento - Admin"],"description":"Reconcilia as janelas do perfil a partir de uma regra semanal única (Calendly-style). Preserva ids/reservas das janelas que continuam no alvo; desativa (não deleta) janelas fora do alvo com reservas confirmadas futuras; deleta as demais fora do alvo; insere os slots novos. Retorna as contagens da operação.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["duracao_minutos","taxa_centavos","dias"],"properties":{"duracao_minutos":{"type":"integer","minimum":15,"maximum":480},"capacidade_pedidos":{"type":["integer","null"],"minimum":1},"capacidade_itens":{"type":["integer","null"],"minimum":1},"taxa_centavos":{"type":"integer","minimum":0},"dias":{"type":"array","minItems":1,"items":{"type":"object","required":["dia_semana","ativo","inicio","fim"],"properties":{"dia_semana":{"type":"integer","minimum":0,"maximum":6},"ativo":{"type":"boolean"},"inicio":{"type":"string"},"fim":{"type":"string"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"criadas":{"type":"integer"},"mantidas":{"type":"integer"},"atualizadas":{"type":"integer"},"desativadas":{"type":"integer"},"removidas":{"type":"integer"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/janelas/{id}":{"patch":{"summary":"Atualizar janela","tags":["Agendamento - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dia_semana":{"type":"integer","minimum":0,"maximum":6},"hora_inicio":{"type":"string"},"hora_fim":{"type":"string"},"capacidade_pedidos":{"type":["integer","null"],"minimum":1},"capacidade_itens":{"type":["integer","null"],"minimum":1},"taxa_centavos":{"type":"integer","minimum":0},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover janela","tags":["Agendamento - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/bloqueios":{"get":{"summary":"Listar bloqueios de data","tags":["Agendamento - Admin"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar bloqueio de data","tags":["Agendamento - Admin"],"description":"Bloqueia uma data (feriado, inventário). metodo/local_id opcionais restringem o escopo do bloqueio; nulos = bloqueia tudo naquela data.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"string"},"metodo":{"type":["string","null"],"enum":["entrega_local","retirada",null]},"local_id":{"type":["string","null"],"format":"uuid"},"motivo":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/bloqueios/{id}":{"delete":{"summary":"Remover bloqueio de data","tags":["Agendamento - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/regras-produto":{"get":{"summary":"Listar / buscar regra por produto","tags":["Agendamento - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"oneOf":[{"type":"array","items":{"type":"object","additionalProperties":true}},{"type":"object","additionalProperties":true,"nullable":true}]}}}}}}},"/agendamento/regras-produto/{produtoId}":{"put":{"summary":"Upsert de regra por produto","tags":["Agendamento - Admin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"preparo_horas":{"type":["integer","null"],"minimum":0},"metodos_permitidos":{"type":["array","null"],"items":{"type":"string","enum":["entrega_local","retirada"]}},"disponivel_de":{"type":["string","null"]},"disponivel_ate":{"type":["string","null"]},"perecivel":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover regra por produto","tags":["Agendamento - Admin"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/agenda":{"get":{"summary":"Agenda operacional do dia","tags":["Agendamento - Admin"],"description":"Janelas do dia (pelo dia da semana) com ocupação confirmada e pedidos por slot.","parameters":[{"schema":{"type":"string"},"in":"query","name":"data","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/metricas":{"get":{"summary":"Métricas de agendamento no período","tags":["Agendamento - Admin"],"description":"total_agendados, ocupação média, taxa arrecadada e reagendamentos (via pedido_status_log) no período.","parameters":[{"schema":{"type":"string"},"in":"query","name":"de","required":true},{"schema":{"type":"string"},"in":"query","name":"ate","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/agendamento/pedidos/{id}/reagendar":{"post":{"summary":"Reagendar a janela de um pedido (lojista)","tags":["Agendamento - Admin"],"description":"Reagenda um pedido já com agendamento para uma nova janela/data, sem trava de antecedência. Mesma saga transacional segura do endpoint público. Escopado por account_id do JWT.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["janela_id","data"],"properties":{"janela_id":{"type":"string","format":"uuid"},"data":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"motivo":{"type":"string"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/shipping/carriers":{"get":{"summary":"Listar transportadoras do tenant","tags":["Logística - Transportadoras"],"description":"Retorna todas as transportadoras configuradas para o tenant (Melhor Envio, Frenet, etc.), com status de saúde e dados de configuração (sem credenciais).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","description":"Identificador do provedor (melhor_envios, frenet, etc.)"},"ativo":{"type":"boolean"},"cep_origem":{"type":["null","string"]},"embalagem_padrao":{"type":["null","object"],"additionalProperties":true},"config":{"type":["null","object"],"additionalProperties":true},"testado_em":{"type":["null","string"],"format":"date-time"},"health_status":{"type":["null","string"],"enum":["healthy","degraded",null]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}},"post":{"summary":"Conectar transportadora","tags":["Logística - Transportadoras"],"description":"Conecta uma nova transportadora ao tenant. Token e webhook_secret são criptografados com AES-GCM antes de persistir. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["provider","token"],"properties":{"provider":{"type":"string","description":"ID do provedor (melhor_envios, frenet, etc.)"},"token":{"type":"string","description":"Token/API key do provedor"},"webhook_secret":{"type":"string","description":"Secret para validação de webhooks"},"cep_origem":{"type":"string","description":"CEP de despacho (8 dígitos)"},"embalagem_padrao":{"type":"object","properties":{"peso_g":{"type":"integer"},"largura_cm":{"type":"integer"},"altura_cm":{"type":"integer"},"comprimento_cm":{"type":"integer"}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transportadora conectada (upsert por account_id+provider)","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Transportadora conectada (upsert por account_id+provider)"}}}}}}},"/shipping/carriers/{id}":{"patch":{"summary":"Atualizar configuração de transportadora","tags":["Logística - Transportadoras"],"description":"Atualiza config JSONB, embalagem padrão e/ou CEP de origem de uma transportadora. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"config":{"type":"object","description":"Configuração livre (JSONB)"},"embalagem_padrao":{"type":"object","properties":{"peso_g":{"type":"integer"},"largura_cm":{"type":"integer"},"altura_cm":{"type":"integer"},"comprimento_cm":{"type":"integer"}}},"cep_origem":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transportadora atualizada","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Transportadora atualizada"}}}}}},"delete":{"summary":"Remover transportadora","tags":["Logística - Transportadoras"],"description":"Remove permanentemente uma transportadora e suas credenciais criptografadas. Invalida cache de cotação. Roles: owner, manager.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removida com sucesso"}}}},"/shipping/carriers/{id}/ativar":{"patch":{"summary":"Ativar ou desativar transportadora","tags":["Logística - Transportadoras"],"description":"Alterna o status ativo/inativo de uma transportadora. Transportadoras inativas não participam da cotação de frete. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ativo"],"properties":{"ativo":{"type":"boolean"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Transportadora atualizada","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Transportadora atualizada"}}}}}}},"/shipping/carriers/{id}/testar":{"post":{"summary":"Testar credenciais da transportadora","tags":["Logística - Transportadoras"],"description":"Executa health check contra a API do provedor usando as credenciais salvas. Atualiza testado_em e health_status (healthy/degraded). Roles: owner, manager.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["carrier_not_found_or_no_credentials"]}}}}}}}}},"/shipping/rules":{"get":{"summary":"Listar regras de frete","tags":["Logística - Regras de Frete"],"description":"Retorna todas as regras de frete do tenant ordenadas por prioridade (campo \"ordem\"). Tipos: entrega_propria, motoboy, tabela_fixa.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"tipo":{"type":"string","enum":["entrega_propria","motoboy","tabela_fixa"]},"nome_exibicao":{"type":"string"},"ativo":{"type":"boolean"},"config":{"type":"object","additionalProperties":true},"ordem":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}}}}}}}},"post":{"summary":"Criar regra de frete","tags":["Logística - Regras de Frete"],"description":"Cria uma nova regra de frete própria (entrega_propria, motoboy ou tabela_fixa) com configuração livre em JSONB. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo","nome_exibicao","config"],"properties":{"tipo":{"type":"string","enum":["entrega_propria","motoboy","tabela_fixa"]},"nome_exibicao":{"type":"string","description":"Nome exibido no checkout (ex: \"Entrega local até 5km\")"},"ativo":{"type":"boolean","default":true},"config":{"type":"object","description":"Configuração da regra (faixas CEP, preço fixo, etc.)"},"ordem":{"type":"integer","default":0,"description":"Prioridade de exibição (menor = primeiro)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Regra criada","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Regra criada"}}}}}}},"/shipping/rules/{id}":{"patch":{"summary":"Atualizar regra de frete","tags":["Logística - Regras de Frete"],"description":"Atualiza campos de uma regra de frete existente: nome, status ativo, config e/ou ordem. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome_exibicao":{"type":"string"},"ativo":{"type":"boolean"},"config":{"type":"object","additionalProperties":true},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Regra atualizada","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"description":"Regra atualizada"}}}}}},"delete":{"summary":"Remover regra de frete","tags":["Logística - Regras de Frete"],"description":"Remove permanentemente uma regra de frete e invalida cache de cotação. Roles: owner, manager.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removida com sucesso"}}}},"/transportadoras-rastreio":{"get":{"summary":"Transportadoras para o rastreio","tags":["Logística - Rastreio"],"description":"As do catálogo (padrao) e as cadastradas pela loja (da_loja), cada uma com nome e modelo de link com {codigo}.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"padrao":{"type":"array","items":{"type":"object","additionalProperties":true}},"da_loja":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"post":{"summary":"Cadastrar transportadora","tags":["Logística - Rastreio"],"description":"Cria uma transportadora da loja. url_modelo: link de rastreio com {codigo} no lugar do código (opcional). Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","maxLength":200},"url_modelo":{"type":["string","null"],"maxLength":2100}},"required":["nome"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/transportadoras-rastreio/{id}":{"patch":{"summary":"Editar transportadora","tags":["Logística - Rastreio"],"description":"Muda nome e/ou modelo de link. Pedidos já enviados guardam o nome e o link do momento do envio. Roles: owner, manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","maxLength":200},"url_modelo":{"type":["string","null"],"maxLength":2100}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir transportadora","tags":["Logística - Rastreio"],"description":"Remove a transportadora da loja. Pedidos já enviados mantêm o nome e o link gravados. Roles: owner, manager.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"}}}},"/shipping/quote":{"post":{"summary":"Cotar frete (engine novo)","tags":["Logística - Cotação de Frete"],"description":"Endpoint público de cotação de frete via engine unificado. Consulta todas as transportadoras ativas e regras do tenant em paralelo. Rate-limited por IP + tenant (header X-Forwarded-For).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","cep_destino","itens"],"properties":{"account_id":{"type":"string","format":"uuid","description":"ID do tenant (loja)"},"cep_destino":{"type":"string","description":"CEP de entrega (8 dígitos)"},"itens":{"type":"array","minItems":1,"items":{"type":"object","required":["produto_id","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"valor_pedido_centavos":{"type":"integer","description":"Valor total do pedido em centavos (para regras de frete grátis)"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"opcoes":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"carrier":{"type":"string"},"provider":{"type":["null","string"]},"servico_codigo":{"type":"string"},"servico_nome":{"type":"string"},"preco_centavos":{"type":"integer"},"prazo_dias":{"type":"integer"},"metadata":{"type":["null","object"],"additionalProperties":true},"despacho_seguro":{"type":["null","object"],"additionalProperties":true,"description":"Presente quando o carrinho tem item perecível e o app \"Entrega e Retirada Agendada\" está ativo.","properties":{"despacho_em":{"type":"string"},"entrega_estimada":{"type":"string"}}}}}},"split":{"type":"boolean","description":"true quando o pedido foi dividido em multiplos envios (multi-CD)"},"envios":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Detalhe por envio quando split=true"},"despacho_seguro_indisponivel":{"type":"boolean","description":"true quando o carrinho tem item perecível mas NENHUMA opção de frete tem despacho seguro nos próximos 14 dias — opções devolvidas SEM filtro/anotação (decisão conservadora: nunca deixar o cliente sem frete)."}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"mensagem":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]},"retry_after_s":{"type":"integer"}}}}}}}}},"/frete/calcular":{"post":{"summary":"Calcular frete (compat legado)","tags":["Logística - Frete Compat"],"description":"Proxy de compatibilidade que usa o engine novo de cotação (/shipping/quote) mas retorna no formato OpcaoFrete do cart-context legado. Mapeia carriers novos para tipos legados (propria, local, melhor_envio, etc.). Rate-limited por IP + tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","cep_destino"],"properties":{"account_id":{"type":"string","format":"uuid","description":"ID do tenant (loja)"},"cep_destino":{"type":"string","description":"CEP de entrega (8 dígitos)"},"itens":{"type":"array","maxItems":50,"items":{"type":"object","required":["produto_id","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"valor_pedido_centavos":{"type":"integer"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"opcoes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string"},"preco":{"type":"integer","description":"Preço em centavos"},"prazo":{"type":"integer","description":"Prazo em dias úteis"},"tipo":{"type":"string","description":"Tipo legado (propria, local, melhor_envio, retirada, frete_gratis, motoboy, tabela_fixa, frenet)"},"provider":{"type":["null","string"],"description":"Provider original do engine"},"servico_id":{"type":["null","integer"],"description":"ID numérico do serviço ME (para emissão de etiqueta)"},"servico_codigo":{"type":"string","description":"Código do serviço no engine. O POST /pedidos aceita em frete.servico_codigo para identificar a opção escolhida."},"shipping_rule_id":{"type":["null","string"],"description":"ID da shipping_rule que originou a opção (entrega_propria/motoboy/tabela_fixa) — null para carriers externos ou frete grátis. Usado pelo checkout para casar a opção com um perfil de agendamento (App Entrega e Retirada Agendada)."},"descricao":{"type":"string"},"partes":{"type":"array","items":{"type":"object","additionalProperties":true}},"despacho_seguro":{"type":["null","object"],"additionalProperties":true,"properties":{"despacho_em":{"type":"string"},"entrega_estimada":{"type":"string"}}}}}},"split":{"type":"boolean","description":"true quando o pedido foi dividido em multiplos envios (multi-CD)"},"envios":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Detalhe por envio quando split=true"},"despacho_seguro_indisponivel":{"type":"boolean"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"mensagem":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]}}}}}}}}},"/frete/promessa":{"post":{"summary":"Promessa de entrega (PDP/vitrine)","tags":["Logística - Frete Compat"],"description":"Resumo compacto da cotação para exibir ao lado do preço na PDP: opção de envio mais barata + mais rápida (padrão VTEX) e primeiro local de retirada. Usa a mesma cotação do /frete/calcular (engine + despacho seguro), com cache consolidado de 120s. mais_rapida vem null quando é a mesma opção da mais_barata. Tudo null = CEP não atendido. Rate-limited por IP + tenant em bucket próprio (separado do /frete/calcular).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","cep_destino"],"properties":{"account_id":{"type":"string","format":"uuid","description":"ID do tenant (loja)"},"cep_destino":{"type":"string","pattern":"^\\d{5}-?\\d{3}$","maxLength":9,"description":"CEP de entrega (8 dígitos, com ou sem hífen)"},"itens":{"type":"array","maxItems":50,"items":{"type":"object","required":["produto_id","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"valor_pedido_centavos":{"type":"integer"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cep_destino":{"type":"string","description":"CEP normalizado (8 dígitos)"},"mais_barata":{"type":["null","object"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"preco":{"type":"integer","description":"Preço em centavos"},"prazo":{"type":"integer","description":"Prazo em dias úteis"},"tipo":{"type":"string","description":"Tipo legado (propria, local, melhor_envio, frete_gratis, motoboy, frenet, correios...)"}},"description":"Opção de ENVIO mais barata (retirada excluída); empate → menor prazo"},"mais_rapida":{"type":["null","object"],"properties":{"id":{"type":"string"},"nome":{"type":"string"},"preco":{"type":"integer","description":"Preço em centavos"},"prazo":{"type":"integer","description":"Prazo em dias úteis"},"tipo":{"type":"string","description":"Tipo legado (propria, local, melhor_envio, frete_gratis, motoboy, frenet, correios...)"}},"description":"Opção de envio mais rápida; empate → menor preço. null quando é a mesma da mais_barata"},"retirada":{"type":["null","object"],"description":"Primeiro local de retirada (principal DESC, ordem ASC); null se a loja não aceita retirada ou não há local ativo","properties":{"local_id":{"type":"string","format":"uuid"},"nome":{"type":"string"},"cidade":{"type":["null","string"]},"uf":{"type":["null","string"]},"prazo_preparo_horas":{"type":["null","integer"]}}},"gratis":{"type":"boolean","description":"true quando mais_barata.preco === 0"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"mensagem":{"type":"string"}}}}}},"429":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["rate_limited"]}}}}}}}}},"/webhook/shipping/frenet/{tenant_id}":{"post":{"summary":"Webhook de rastreio Frenet","tags":["Logística - Shipping Webhooks"],"description":"Recebe eventos de mudança de status de rastreio da Frenet para um tenant específico. Valida assinatura via webhook_secret_enc, localiza pedido por tracking_number, faz dedup e registra no pedido_status_log.","requestBody":{"content":{"application/json":{"schema":{"type":"object","description":"Payload do webhook Frenet (formato proprietário, parseado pelo provider)"}}},"description":"Payload do webhook Frenet (formato proprietário, parseado pelo provider)"},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tenant_id","required":true,"description":"ID do tenant (account_id)"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"ignored":{"type":"string","description":"Motivo se o evento foi ignorado"},"deduped":{"type":"boolean","description":"true se evento já processado"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["unparseable_event"]}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["no_webhook_secret","invalid_signature"]}}}}}}}}},"/index-views":{"get":{"summary":"Listar views salvas","tags":["Views"],"description":"Retorna views customizadas do recurso (filtros salvos para listagens).","parameters":[{"schema":{"type":"string"},"in":"query","name":"recurso","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar view","tags":["Views"],"description":"Salva nova view customizada com nome e filtros para um recurso.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["recurso","nome"],"properties":{"recurso":{"type":"string"},"nome":{"type":"string"},"filtros":{"type":"object"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/index-views/{id}":{"patch":{"summary":"Atualizar view","tags":["Views"],"description":"Atualiza nome ou ordem de uma view salva.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir view","tags":["Views"],"description":"Remove view customizada.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/shipping/melhor-envio/connect":{"post":{"summary":"Iniciar conexão OAuth Melhor Envio","tags":["Logística - Melhor Envio"],"description":"Gera um state criptografado, persiste em shipping_carriers.config e retorna a URL de autorização OAuth2 do Melhor Envio. O frontend redireciona o browser para essa URL. Roles: owner, manager, super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"authorize_url":{"type":"string","format":"uri"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["oauth_not_configured"]},"message":{"type":"string"}}}}}}}}},"/shipping/melhor-envio/callback":{"post":{"summary":"Callback OAuth Melhor Envio","tags":["Logística - Melhor Envio"],"description":"Recebe code+state do redirect OAuth, valida o state contra o armazenado, troca code por access_token+refresh_token e persiste credenciais criptografadas. Busca dados do usuário ME para exibição no admin. Roles: owner, manager, super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string","description":"Authorization code do Melhor Envio"},"state":{"type":"string","description":"State gerado no connect (CSRF protection)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean"},"me_user":{"type":["null","object"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["oauth_exchange_failed"]},"message":{"type":"string"}}}}}}}}},"/shipping/melhor-envio/status":{"get":{"summary":"Verificar status de conexão Melhor Envio","tags":["Logística - Melhor Envio"],"description":"Retorna se o tenant está conectado ao Melhor Envio, dados do usuário ME, data de expiração do token e CEP de origem configurado.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean"},"me_user":{"type":["null","object"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}}},"expires_at":{"type":"string","format":"date-time"},"cep_origem":{"type":["null","string"]},"error":{"type":"string","description":"Presente apenas se connected=false com erro"}}}}}}}}},"/shipping/melhor-envio/disconnect":{"post":{"summary":"Desconectar Melhor Envio","tags":["Logística - Melhor Envio"],"description":"Remove tokens OAuth e desconecta o tenant do Melhor Envio. Roles: owner, manager, super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"disconnected":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/shipping/melhor-envio/services":{"get":{"summary":"Listar serviços Melhor Envio e configuração","tags":["Logística - Melhor Envio"],"description":"Retorna serviços disponíveis na API do ME, configuração local por serviço (ativo, markup, prazo adicional, nome customizado), embalagem padrão e catálogo de embalagens do tenant.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"available":{"type":"array","items":{"type":"object","additionalProperties":true},"description":"Serviços da API Melhor Envio"},"servicos_config":{"type":"array","items":{"type":"object","properties":{"service_id":{"type":"integer"},"ativo":{"type":"boolean"},"nome_customizado":{"type":["null","string"]},"markup_pct":{"type":"number"},"prazo_adicional_dias":{"type":"integer"}}}},"embalagem_padrao":{"type":["null","object"],"additionalProperties":true},"embalagem_padrao_id":{"type":["null","string"]},"embalagens_catalogo":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["me_not_connected"]},"message":{"type":"string"}}}}}}}}},"/shipping/melhor-envio/services-config":{"patch":{"summary":"Salvar configuração de serviços e embalagem","tags":["Logística - Melhor Envio"],"description":"Atualiza a configuração por serviço ME (ativo, markup, prazo adicional, nome customizado) e/ou embalagem padrão. Se embalagem_padrao_id informado, resolve snapshot do catálogo. Invalida cache de cotação. Roles: owner, manager, super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"servicos_config":{"type":"array","items":{"type":"object","required":["service_id","ativo"],"properties":{"service_id":{"type":"integer","description":"ID do serviço no Melhor Envio"},"ativo":{"type":"boolean"},"nome_customizado":{"type":["string","null"]},"markup_pct":{"type":"number","description":"Markup em % sobre o preço do ME"},"prazo_adicional_dias":{"type":"integer","description":"Dias úteis adicionados ao prazo do ME"}}}},"embalagem_padrao":{"type":["object","null"],"properties":{"peso_g":{"type":"integer"},"largura_cm":{"type":"integer"},"altura_cm":{"type":"integer"},"comprimento_cm":{"type":"integer"}},"description":"Override manual de embalagem (limpa embalagem_padrao_id)"},"embalagem_padrao_id":{"type":["string","null"],"format":"uuid","description":"ID de embalagem do catálogo do tenant"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/shipping/melhor-envio/cep-origem":{"patch":{"summary":"Atualizar CEP de origem do despacho","tags":["Logística - Melhor Envio"],"description":"Atualiza o CEP de origem usado nas cotações do Melhor Envio. Valida 8 dígitos. Roles: owner, manager, super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cep_origem":{"type":["string","null"],"description":"CEP de despacho (8 dígitos) ou null para limpar"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"cep_origem":{"type":["null","string"]}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}},"403":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"statusCode":{"type":"integer"},"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/webhook/melhor-envio":{"post":{"summary":"Webhook de eventos Melhor Envio","tags":["Logística - Melhor Envio Webhooks"],"description":"Recebe eventos de mudança de status das etiquetas do Melhor Envio (order.created, order.posted, order.delivered, etc.). Corpo sem evento é a sonda de cadastro do painel ME e recebe 200 sem processar. Evento válido exige assinatura HMAC-SHA256 no header X-ME-Signature. Atualiza status e rastreio do pedido, registra no audit trail e dispara side effects (email \"pedido enviado\", evento order_fulfilled para Flow Builder). Retry policy: 5 tentativas a cada 15min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","description":"Tipo do evento (ex: order.posted, order.delivered)"},"data":{"type":"object","properties":{"id":{"type":"string","description":"ID do pedido/etiqueta no Melhor Envio"},"tracking":{"type":["string","null"],"description":"Código de rastreio"},"tracking_url":{"type":["string","null"],"description":"URL de rastreio"}}}}}}}},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-me-signature","required":false,"description":"HMAC-SHA256(rawBody, CLIENT_SECRET) em base64"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string","format":"uuid"}}}}}},"401":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["invalid_signature"]}}}}}}}}},"/diagnostico/frete":{"post":{"summary":"Rodar cotação de diagnóstico (sem cache, sem alimentar o circuit breaker)","tags":["Diagnóstico"],"description":"Executa o mesmo caminho de cotação da loja, ignorando cache e circuito, sem escrever em nenhum dos dois. Devolve o veredito em português e o corpo cru que a transportadora respondeu. Papéis: owner, manager, super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cep_destino"],"properties":{"account_id":{"type":"string","format":"uuid","description":"Só super_admin pode diagnosticar outro tenant"},"cep_destino":{"type":"string"},"cep_origem":{"type":"string","description":"Testar uma origem antes de salvá-la"},"itens":{"type":"array","maxItems":20,"items":{"type":"object","required":["produto_id","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1}}}},"pacote":{"type":"object","description":"Peso e medidas na mão, para tenant que ainda não tem catálogo","required":["peso_g"],"properties":{"peso_g":{"type":"integer","minimum":1},"largura_cm":{"type":"integer","minimum":1},"altura_cm":{"type":"integer","minimum":1},"comprimento_cm":{"type":"integer","minimum":1},"valor_centavos":{"type":"integer","minimum":0}}},"valor_pedido_centavos":{"type":"integer","minimum":0}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/diagnostico/{id}/reexecutar":{"post":{"summary":"Repetir um diagnóstico com a mesma entrada","tags":["Diagnóstico"],"description":"Refaz exatamente o caso registrado — é o \"testar de novo depois da correção\" sem precisar redigitar nada. Papéis: owner, manager, super_admin.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/diagnostico":{"get":{"summary":"Histórico de diagnósticos do tenant","tags":["Diagnóstico"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","enum":["frete","pagamento"]},"in":"query","name":"dominio","required":false},{"schema":{"type":"integer","minimum":1,"maximum":50,"default":10},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/internal/emails/enviar":{"post":{"summary":"Enviar e-mail de automação (Flow Builder)","tags":["Interno - E-mails"],"description":"Compõe e envia e-mail com branding do tenant (Brand Kit). Rota interna service-to-service autenticada via X-Internal-Key — usada pelo nó msg_email do Flow Builder no Connect.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","to","assunto","corpo"],"properties":{"account_id":{"type":"string","format":"uuid"},"to":{"type":"string"},"assunto":{"type":"string"},"corpo":{"type":"string"},"cta_texto":{"type":["string","null"]},"cta_url":{"type":["string","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true,"description":"Chave interna service-to-service"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"additionalProperties":true}}}}}}},"/internal/ia/alerta-cota":{"post":{"summary":"Alertar lojista sobre cota de IA (80% ou esgotada)","tags":["Interno - E-mails"],"description":"Dispara o e-mail de alerta de cota de mensagens de IA. Idempotente por (tenant, mês, recurso, marco) via ia_alertas_cota: chamar a cada turno não reenvia. Rota interna service-to-service autenticada via X-Internal-Key.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id"],"properties":{"account_id":{"type":"string","format":"uuid"},"recurso":{"type":"string","description":"Medidor alertado. Default 'mensagens_ia'."}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true,"description":"Chave interna service-to-service"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"enviado":{"type":"boolean"},"motivo":{"type":"string"},"nivel":{"type":"number"}},"additionalProperties":true}}}}}}},"/internal/cupons/individual":{"post":{"summary":"Gerar cupom individual (Flow Builder)","tags":["Interno - Cupons"],"description":"Cria um cupom percentual de uso único e prazo curto para uma pessoa da régua. Idempotente pela chave (execução + nó). Rota interna service-to-service autenticada via X-Internal-Key, usada pelo nó acao_gerar_cupom do Connect.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","percentual","validade_horas","chave"],"properties":{"account_id":{"type":"string","format":"uuid"},"percentual":{"type":"number"},"validade_horas":{"type":"integer"},"chave":{"type":"string"},"prefixo":{"type":"string"},"rotulo":{"type":["string","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"header","name":"x-internal-key","required":true,"description":"Chave interna service-to-service"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"codigo":{"type":"string"},"validade_fim":{"type":"string"},"reaproveitado":{"type":"boolean"}}}}}}}}},"/locations":{"get":{"summary":"Listar locais","tags":["Localizações"],"description":"Locais físicos do tenant com filtros por flags (retirada, estoque, despacho, ativo).","parameters":[{"schema":{"type":"string"},"in":"query","name":"serve_retirada","required":false},{"schema":{"type":"string"},"in":"query","name":"serve_estoque","required":false},{"schema":{"type":"string"},"in":"query","name":"serve_despacho","required":false},{"schema":{"type":"string"},"in":"query","name":"ativo","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar local","tags":["Localizações"],"description":"Cria local com flags de função (estoque, retirada, despacho). Se principal=true, desmarca os outros.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"cep":{"type":"string"},"logradouro":{"type":"string"},"numero":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"},"serve_estoque":{"type":"boolean"},"serve_retirada":{"type":"boolean"},"serve_despacho":{"type":"boolean"},"principal":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/locations/{accountId}":{"get":{"summary":"Locais de retirada (público)","tags":["Localizações"],"description":"Locais ativos de retirada para checkout. Endpoint público.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/locations/{id}":{"patch":{"summary":"Atualizar local","tags":["Localizações"],"description":"Atualização parcial via whitelist. Se principal=true, desmarca os outros.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir local","tags":["Localizações"],"description":"Remove local do tenant. Invalida cache de shipping.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/locations/routing-config":{"get":{"summary":"Config de roteamento Multi-CD","tags":["Localizações"],"description":"Retorna as regras de roteamento (ordem de prioridade), se split de envio é permitido, e quantos locais servem despacho.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"put":{"summary":"Atualizar config de roteamento Multi-CD","tags":["Localizações"],"description":"Grava as regras de roteamento (ordem de prioridade) e a flag de permitir split de envio.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"regras":{"type":"array"},"permitir_split":{}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/pdv/sessao":{"get":{"summary":"Dados da sessão PDV","tags":["PDV - Ponto de Venda"],"description":"Retorna config_pdv, locais, categorias com contagem de produtos e dados do operador. Bloqueia role assistant.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/produtos/buscar":{"post":{"summary":"Buscar produtos","tags":["PDV - Ponto de Venda"],"description":"Busca por nome, SKU ou EAN. Aceita filtro por categoria. Retorna fotos de capa e variações.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"categoria_id":{"type":"string"},"local_id":{"type":"string"},"limit":{"type":"integer","default":30}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/pessoas/buscar":{"post":{"summary":"Buscar pessoas","tags":["PDV - Ponto de Venda"],"description":"Busca unificada em clientes por nome, email, telefone ou CPF. Retorna lifecycle_stage e origem_canais.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["query"],"properties":{"query":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/pessoas/selecionar":{"post":{"summary":"Selecionar cliente","tags":["PDV - Ponto de Venda"],"description":"Seleciona cliente para a venda. Promove lead para prospect automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/creditos/{clienteId}":{"get":{"summary":"Saldo de créditos do cliente (PDV)","tags":["PDV - Ponto de Venda"],"description":"Retorna saldo disponível e parâmetros de uso (teto, mínimo, cumulativo com cupom) para aplicar créditos no balcão. Gated pelo acesso ao PDV.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"clienteId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/finalizar":{"post":{"summary":"Finalizar venda PDV","tags":["PDV - Ponto de Venda"],"description":"Cria pedido completo. Dinheiro/cartão = confirmado direto. Pix = pendente + QR code. Valida estoque, desconto, CPF obrigatório e gateway.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["local_origem_id","itens","tipo_entrega","forma_pagamento"],"properties":{"local_origem_id":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"lote_codigo":{"type":["string","null"],"maxLength":20,"description":"Lote bipado (GS1 AI 10). Baixa dirigida com fallback FEFO."}}}},"tipo_entrega":{"type":"string","enum":["envio","retirada"]},"forma_pagamento":{"type":"string","enum":["pix","dinheiro","cartao_externo","creditos"]},"creditos_usados_centavos":{"type":"integer","minimum":0,"nullable":true},"cliente_id":{"type":["string","null"]},"cliente":{"type":["object","null"],"additionalProperties":true},"desconto_percentual":{"type":"number"},"endereco":{"type":["object","null"],"additionalProperties":true},"frete":{"type":["object","null"],"additionalProperties":true},"agendamento":{"type":["object","null"],"additionalProperties":true},"observacao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"lote_fallback":{"type":"boolean","description":"true quando algum lote bipado não pôde ser baixado e a venda caiu no FEFO."},"local_fallback":{"type":"boolean","description":"true quando algum item foi baixado no CD principal por não ter estoque cadastrado no local da venda (regra de compatibilidade D1)."}}}}}}}}},"/pdv/pausar":{"post":{"summary":"Pausar venda (Park Sale)","tags":["PDV - Ponto de Venda"],"description":"Salva venda em andamento como rascunho. Cliente opcional.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["local_origem_id","itens"],"properties":{"local_origem_id":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"cliente_id":{"type":["string","null"]},"cliente":{"type":["object","null"],"additionalProperties":true},"desconto_percentual":{"type":"number"},"observacao":{"type":"string"},"tipo_entrega":{"type":"string"},"endereco":{"type":["object","null"],"additionalProperties":true},"frete":{"type":["object","null"],"additionalProperties":true},"razao_desconto":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/vendas-pausadas":{"get":{"summary":"Vendas pausadas","tags":["PDV - Ponto de Venda"],"description":"Lista rascunhos PDV do operador atual. Filtro por local.","parameters":[{"schema":{"type":"string"},"in":"query","name":"local_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/vendas-pausadas/{id}/retomar":{"post":{"summary":"Retomar venda pausada","tags":["PDV - Ponto de Venda"],"description":"Consome o rascunho e devolve itens, cliente, desconto e entrega para hidratar o carrinho do PDV.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/pedidos/{id}/status":{"get":{"summary":"Status do pedido (polling)","tags":["PDV - Ponto de Venda"],"description":"Polling leve para detectar pagamento Pix. Frontend chama a cada 3s.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/cotar-frete":{"post":{"summary":"Cotar frete PDV","tags":["PDV - Ponto de Venda"],"description":"Cotação autenticada via shipping engine para ship-later.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cep_destino","itens"],"properties":{"cep_destino":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"valor_pedido_centavos":{"type":"integer"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/enviar-pix-whatsapp":{"post":{"summary":"Enviar Pix via WhatsApp","tags":["PDV - Ponto de Venda"],"description":"Envia código Pix copia-e-cola via Connect (Evolution/WABA).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_id","pix_code"],"properties":{"pedido_id":{"type":"string"},"pix_code":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/recibo-whatsapp":{"post":{"summary":"Enviar recibo via WhatsApp","tags":["PDV - Ponto de Venda"],"description":"Envia recibo do pedido por WhatsApp com link de acompanhamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_id"],"properties":{"pedido_id":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/pdv/pedidos/{id}/recibo":{"get":{"summary":"Dados do recibo do pedido (cupom não-fiscal)","tags":["PDV - Ponto de Venda"],"description":"Read-only. Consolida pedido + itens + dados_extras.pdv + config_pdv pra render do cupom térmico. Reimpressão de pedido antigo.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"loja":{"type":"object","additionalProperties":true},"pedido":{"type":"object","additionalProperties":true},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"totais":{"type":"object","additionalProperties":true},"pdv":{"type":"object","additionalProperties":true,"properties":{"forma_pagamento":{"type":["null","string"]},"recebido_centavos":{"type":["null","integer"]},"troco_centavos":{"type":["null","integer"]},"bandeira":{"type":["null","string"]},"parcelas":{"type":["null","integer"]}}},"link_acompanhamento":{"type":"string"}}}}}}}}},"/pdv/caixa/abrir":{"post":{"summary":"Abrir caixa","tags":["PDV - Caixa"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["local_id"],"properties":{"local_id":{"type":"string"},"valor_abertura_centavos":{"type":"integer","minimum":0,"nullable":true},"terminal":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/atual":{"get":{"summary":"Caixa aberto do local","tags":["PDV - Caixa"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"local_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/{id}/sangria":{"post":{"summary":"Sangria (retirada de dinheiro)","tags":["PDV - Caixa"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["valor_centavos","motivo"],"properties":{"valor_centavos":{"type":"integer","minimum":1},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/{id}/suprimento":{"post":{"summary":"Suprimento (entrada de dinheiro)","tags":["PDV - Caixa"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["valor_centavos","motivo"],"properties":{"valor_centavos":{"type":"integer","minimum":1},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/{id}/conferencia":{"get":{"summary":"Conferência (esperado server-side)","tags":["PDV - Caixa"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/{id}/fechar":{"post":{"summary":"Fechar caixa (Relatório Z)","tags":["PDV - Caixa"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"contado_por_forma":{"type":"object","additionalProperties":true},"observacao":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa/{id}/relatorio-z":{"get":{"summary":"Relatório Z","tags":["PDV - Caixa"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/caixa":{"get":{"summary":"Histórico de caixas","tags":["PDV - Caixa"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"local_id","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false},{"schema":{"type":"string"},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/pedidos/buscar-devolucao":{"get":{"summary":"Buscar pedidos elegíveis para devolução","tags":["PDV - Devolução"],"description":"Busca por número, CPF ou telefone. Retorna pedidos PDV elegíveis com itens, quantidade comprada e disponível para devolução. Requer owner/manager.","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"string"},"in":"query","name":"local_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/devolucao/calcular":{"post":{"summary":"Calcular valor de devolução (preview, sem efeito)","tags":["PDV - Devolução"],"description":"Fonte de verdade do valor de reembolso exibido na UI. Re-valida quantidades server-side. Requer owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_id","itens"],"additionalProperties":true,"properties":{"pedido_id":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pdv/devolucao":{"post":{"summary":"Registrar devolução de balcão","tags":["PDV - Devolução"],"description":"Cria a devolução, repõe estoque e restitui o cliente (dinheiro/cartão-pix/crédito-loja) via refund unificado. Idempotente por idempotency_key. Requer owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pedido_id","itens","metodo_reembolso","motivo"],"additionalProperties":true,"properties":{"pedido_id":{"type":"string"},"itens":{"type":"array","items":{"type":"object","additionalProperties":true}},"tipo":{"type":"string","enum":["devolucao","troca"],"default":"devolucao"},"metodo_reembolso":{"type":"string","enum":["dinheiro","estorno_cartao","credito_loja","pix"]},"motivo":{"type":"string","minLength":1},"local_id":{"type":["string","null"]},"idempotency_key":{"type":["string","null"]}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pedidos/{id}/link-pagamento":{"get":{"summary":"Obter link de pagamento do pedido","tags":["Checkout - Pedidos via Link"],"description":"Retorna URL pública de acompanhamento/pagamento do pedido para envio ao cliente. Indica se pode enviar via WhatsApp ou email. Padrão Shopify Send Invoice.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"string"},"pedido_numero":{"type":"string","nullable":true},"total_centavos":{"type":"integer"},"status":{"type":"string"},"ja_pago":{"type":"boolean"},"cliente_telefone":{"type":"string","nullable":true},"cliente_email":{"type":"string","nullable":true},"pode_whatsapp":{"type":"boolean"},"pode_email":{"type":"boolean"}}}}}}}}},"/pedidos/{id}/link-pagamento/enviar":{"post":{"summary":"Enviar link de pagamento ao cliente","tags":["Checkout - Pedidos via Link"],"description":"Envia o link de pagamento ao cliente via WhatsApp (Connect interno ou wa.me fallback) ou email (pendente). Bloqueia envio se pedido já está pago.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"canal":{"type":"string","enum":["whatsapp","email"],"default":"whatsapp"},"mensagem_extra":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"enviado":{"type":"boolean"},"canal":{"type":"string"},"link":{"type":"string"},"wa_url":{"type":"string","nullable":true,"description":"Fallback wa.me URL quando envio direto falha"}}}}}}}}},"/estudio/projetos":{"get":{"summary":"Listar projetos","tags":["Conteúdo - Estúdio IA"],"description":"Lista projetos do Estúdio IA do tenant com filtro por status e busca.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"search","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar projeto","tags":["Conteúdo - Estúdio IA"],"description":"Cria projeto no Estúdio IA.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["titulo"],"properties":{"titulo":{"type":"string"},"descricao":{"type":"string"},"origem":{"type":"string"},"origem_ref":{}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/projetos/{id}":{"get":{"summary":"Detalhe do projeto","tags":["Conteúdo - Estúdio IA"],"description":"Retorna projeto com nós e edges do canvas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar projeto","tags":["Conteúdo - Estúdio IA"],"description":"Atualiza título, descrição, status ou capa do projeto.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir projeto","tags":["Conteúdo - Estúdio IA"],"description":"Remove projeto e seus nós/edges (cascade).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/projetos/{projetoId}/nos":{"post":{"summary":"Criar nó","tags":["Conteúdo - Estúdio IA"],"description":"Adiciona nó ao canvas do projeto com tipo, posição e conteúdo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo","posicao"],"properties":{"tipo":{"type":"string"},"posicao":{"type":"object"},"tamanho":{"type":"object"},"conteudo":{"type":"object"},"config":{"type":"object"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"projetoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/projetos/{projetoId}/nos/{noId}":{"patch":{"summary":"Atualizar nó","tags":["Conteúdo - Estúdio IA"],"description":"Auto-save de posição, tamanho, conteúdo ou config do nó.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"projetoId","required":true},{"schema":{"type":"string"},"in":"path","name":"noId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir nó","tags":["Conteúdo - Estúdio IA"],"description":"Remove nó do canvas.","parameters":[{"schema":{"type":"string"},"in":"path","name":"projetoId","required":true},{"schema":{"type":"string"},"in":"path","name":"noId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/projetos/{projetoId}/edges":{"post":{"summary":"Criar conexão","tags":["Conteúdo - Estúdio IA"],"description":"Adiciona edge (conexão) entre dois nós.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["source_id","target_id"],"properties":{"source_id":{"type":"string"},"target_id":{"type":"string"},"source_handle":{"type":"string"},"target_handle":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"projetoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/projetos/{projetoId}/edges/{edgeId}":{"delete":{"summary":"Remover conexão","tags":["Conteúdo - Estúdio IA"],"description":"Remove edge entre nós.","parameters":[{"schema":{"type":"string"},"in":"path","name":"projetoId","required":true},{"schema":{"type":"string"},"in":"path","name":"edgeId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/creditos":{"get":{"summary":"Saldo de créditos","tags":["Conteúdo - Estúdio IA"],"description":"Retorna saldo de créditos IA do tenant (mensal + addon + limite do plano). Aplica lazy reset mensal ao consultar.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/sidebar-dados":{"get":{"summary":"Dados para sidebar","tags":["Conteúdo - Estúdio IA"],"description":"Agrega produtos, clientes top, segmentos, métricas e reels para drag-drop no canvas.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/projetos/{id}/gerar":{"post":{"summary":"Gerar peças criativas","tags":["Conteúdo - Estúdio IA Geração"],"description":"Gera imagens e textos IA em batch. Debita créditos antecipadamente. Processamento em background (202 Accepted).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto","angulo","saidas"],"properties":{"produto":{"type":"object"},"angulo":{"type":"string"},"saidas":{"type":"array","items":{"type":"object","additionalProperties":true}},"tom":{"type":"string"},"contextoCliente":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/projetos/{id}/assets":{"get":{"summary":"Listar assets do projeto","tags":["Conteúdo - Estúdio IA Geração"],"description":"Polling de assets gerados. Frontend chama para acompanhar status de geração.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/estudio/video/disponibilidade":{"get":{"summary":"Disponibilidade do vídeo com IA","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Diz se o botão aparece, modelos com preço por duração e som, formatos, estilos e saldo.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/videos":{"post":{"summary":"Criar vídeo do produto com IA","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Debita créditos e envia a geração. 202 com o asset em gerando. Estorno automático em falha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"produto_id":{"type":"string"},"imagem_url":{"type":["string","null"]},"estilo":{"type":"string"},"formato":{"type":"string"},"duracao":{"type":"number"},"texto":{"type":["string","null"]},"projeto_id":{"type":["string","null"]},"modelo":{"type":["string","null"]},"audio":{"type":["boolean","null"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Vídeos com IA da loja","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Galeria: os vídeos da loja (do produto e UGC), mais recentes primeiro. Avança os que estão gerando.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/videos/ugc":{"post":{"summary":"Criar vídeo UGC com IA","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Vídeo de uma pessoa falando do produto (Higgsfield). Com quadro inicial (e final, opcional) vai pelo image-to-video do Seedance ou pelo first-last-frame do Kling O3. Preço e pedido ao provedor montados no servidor. 202 com o asset em gerando; estorno automático em falha. Header Idempotency-Key opcional (8 a 120 caracteres): repetição com a mesma chave em até 15 min, com o asset gerando ou pronto, devolve o mesmo asset sem debitar; asset que falhou segue como pedido novo.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"produto_ids":{"type":"array","items":{"type":"string"}},"pessoa_id":{"type":"string"},"modelo_ia":{"type":"string"},"resolucao":{"type":["string","null"]},"duracao":{"type":"number"},"formato":{"type":"string"},"som":{"type":"boolean"},"diretor":{"type":["string","null"]},"prompt":{"type":"string"},"ref_card":{"type":["string","null"]},"quadro_inicial":{"type":["object","null"],"additionalProperties":true},"quadro_final":{"type":["object","null"],"additionalProperties":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/assets/{assetId}":{"get":{"summary":"Consultar asset do Estúdio","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Devolve o asset. Vídeo em gerando é avançado na hora (consulta o provedor e copia para o storage).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"assetId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/produtos/{produtoId}/videos":{"get":{"summary":"Vídeos com IA do produto","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Lista os vídeos do produto (mais recentes primeiro) e avança os que estão gerando. Fonte de verdade do painel do produto.","parameters":[{"schema":{"type":"string"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/imagens":{"post":{"summary":"Criar criativos de foto com IA","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"IA Studio: reproduz um modelo da galeria com a foto do produto (Higgsfield). Preço, prompt e referências montados no servidor. 202 com os assets em gerando; estorno automático em falha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"produto_id":{"type":"string"},"modelo_criativo":{"type":"string"},"modelo_ia":{"type":"string"},"formato":{"type":"string"},"quantidade":{"type":"integer"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Criativos de foto da loja","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"IA Studio: os criativos de foto da loja, mais recentes primeiro. Avança os que estão gerando.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/imagens/tema":{"post":{"summary":"Criar imagem do editor de tema com IA","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Editor de tema: gera uma imagem na medida exata do espaço (ex.: banner 1920 x 640) com os modelos e estilos do IA Studio, a partir da descrição do lojista e, se quiser, da foto de um produto. Só o texto aprovado vai na imagem. 202 com o asset em gerando; estorno automático em falha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"descricao":{"type":"string"},"largura":{"type":"integer"},"altura":{"type":"integer"},"modelo_ia":{"type":"string"},"produto_id":{"type":["string","null"]},"modelo_criativo":{"type":["string","null"]},"texto":{"type":["string","null"]},"tema_id":{"type":"string"},"tema_nome":{"type":"string"},"destino":{"type":"object","additionalProperties":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"202":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"402":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"502":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/estudio/imagens/{assetId}/recorte":{"post":{"summary":"Recortar uma criação na medida de um espaço do tema","tags":["Conteúdo - Estúdio IA Vídeo"],"description":"Editor de tema: o lojista escolheu no IA Studio uma criação de foto que já existe. Devolve a URL dela na medida exata do espaço (cópia recortada, ou a própria quando já está na medida). Não cobra créditos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"largura":{"type":"integer"},"altura":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"assetId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/cross-sell":{"get":{"summary":"Listar regras de cross-sell","tags":["Apps - Cross-sell"],"description":"Retorna regras de cross-sell do tenant, ordenadas por peso decrescente. Requer role manager+.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar regra de cross-sell","tags":["Apps - Cross-sell"],"description":"Cria regra manual ou algorítmica de cross-sell. Invalida cache do tenant. Requer role manager+.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string","default":"manual"},"produto_origem_id":{"type":["string","null"],"format":"uuid"},"categoria_origem":{"type":["string","null"]},"produtos_destino":{"type":"array","items":{"type":"string","format":"uuid"}},"algoritmo":{"type":"string","default":"co_purchase"},"peso":{"type":"integer","default":10},"ativo":{"type":"boolean","default":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cross-sell/{id}":{"put":{"summary":"Atualizar regra de cross-sell","tags":["Apps - Cross-sell"],"description":"Atualiza campos parciais de uma regra. Invalida cache do tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string"},"produto_origem_id":{"type":["string","null"]},"categoria_origem":{"type":["string","null"]},"produtos_destino":{"type":"array","items":{"type":"string"}},"algoritmo":{"type":"string"},"peso":{"type":"integer"},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover regra de cross-sell","tags":["Apps - Cross-sell"],"description":"Remove regra de cross-sell (hard delete). Invalida cache do tenant.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/cross-sell/recomendacoes/{produtoId}":{"get":{"summary":"Recomendações de cross-sell (público)","tags":["Apps - Cross-sell"],"description":"Retorna produtos recomendados para o storefront. Engine de 3 camadas: regras manuais (prioridade máxima) -> co-purchase (90 dias) -> mesma categoria (fallback). Cache in-memory 5min.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"integer","default":6,"maximum":12},"in":"query","name":"limit","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/fidelidade/config":{"get":{"summary":"Ler configuração de fidelidade (admin)","tags":["Apps - Fidelidade"],"description":"Retorna configuração do programa de fidelidade. Se não existe, retorna defaults (lazy creation). Requer role owner/manager.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Salvar configuração de fidelidade","tags":["Apps - Fidelidade"],"description":"Upsert da configuração do programa. Campos: ativo, nome_programa, pontos_por_real, minimo_resgate, etc.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"},"nome_programa":{"type":"string"},"pontos_por_real":{"type":"number"},"minimo_resgate":{"type":"integer"},"valor_ponto_centavos":{"type":"integer"},"pontos_cadastro":{"type":"integer"},"pontos_aniversario":{"type":"integer"},"validade_dias":{"type":"integer"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/tiers":{"get":{"summary":"Listar tiers de fidelidade","tags":["Apps - Fidelidade"],"description":"Retorna tiers ordenados por ordem.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar tier de fidelidade","tags":["Apps - Fidelidade"],"description":"Cria um novo tier com nome, pontos mínimos, multiplicador, cor e ícone.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","pontos_minimos"],"properties":{"nome":{"type":"string"},"pontos_minimos":{"type":"integer"},"multiplicador":{"type":"number","default":1},"cor":{"type":"string","default":"#94a3b8"},"icone":{"type":"string","default":"Star"},"ordem":{"type":"integer","default":0}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/tiers/{id}":{"put":{"summary":"Atualizar tier de fidelidade","tags":["Apps - Fidelidade"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"pontos_minimos":{"type":"integer"},"multiplicador":{"type":"number"},"cor":{"type":"string"},"icone":{"type":"string"},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir tier de fidelidade","tags":["Apps - Fidelidade"],"description":"Remove tier. Retorna 409 se houver clientes vinculados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/tiers/reorder":{"put":{"summary":"Reordenar tiers","tags":["Apps - Fidelidade"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["ids"],"properties":{"ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/fidelidade/movimentacoes":{"get":{"summary":"Listar movimentações de fidelidade","tags":["Apps - Fidelidade"],"description":"Movimentações paginadas com filtro por cliente_id e tipo.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"cliente_id","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":100},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/ranking":{"get":{"summary":"Ranking de clientes por pontos","tags":["Apps - Fidelidade"],"description":"Top clientes por pontos acumulados com dados de tier.","parameters":[{"schema":{"type":"integer","default":10,"maximum":50},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/fidelidade/dashboard":{"get":{"summary":"Dashboard de fidelidade","tags":["Apps - Fidelidade"],"description":"Retorna total emitidos, resgatados, clientes ativos e distribuição por tier.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/bonificar":{"post":{"summary":"Bonificar pontos manualmente","tags":["Apps - Fidelidade"],"description":"Adiciona pontos de bonificação a um cliente. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","pontos"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"pontos":{"type":"integer","minimum":1},"descricao":{"type":"string","default":"Bonificação manual"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/public/saldo":{"get":{"summary":"Saldo de fidelidade do cliente logado","tags":["Apps - Fidelidade"],"description":"Retorna saldo, tier atual, tiers disponíveis, configuração e últimas 20 movimentações. Autenticação via x-user-id (JWT do cliente OTP).","responses":{"200":{"description":"Default Response"}}}},"/fidelidade/public/resgatar":{"post":{"summary":"Resgatar pontos de fidelidade","tags":["Apps - Fidelidade"],"description":"Cliente autenticado resgata pontos, que geram cupom de desconto. Cliente derivado do token (x-user-id).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["pontos"],"properties":{"pontos":{"type":"integer","minimum":1}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/public/config":{"get":{"summary":"Configuração pública de fidelidade","tags":["Apps - Fidelidade"],"description":"Retorna config pública (sem dados sensíveis) e tiers para o storefront verificar se o programa está ativo.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/fidelidade/saldo/{clienteId}":{"get":{"summary":"Saldo de fidelidade de um cliente (admin)","tags":["Apps - Fidelidade"],"description":"Retorna saldo, tier e últimas 50 movimentações de um cliente específico.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"clienteId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creditos/saldo/{clienteId}":{"get":{"summary":"Saldo de créditos de um cliente (admin)","tags":["Apps - Cashback"],"description":"Retorna saldo (disponível + pendente) e as últimas 10 movimentações do extrato. Requer role owner/manager.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"clienteId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creditos/extrato/{clienteId}":{"get":{"summary":"Extrato de créditos de um cliente (admin)","tags":["Apps - Cashback"],"description":"Extrato paginado de transações de créditos do cliente. Requer role owner/manager.","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"pageSize","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"clienteId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creditos/ajuste":{"post":{"summary":"Ajuste manual de créditos (admin)","tags":["Apps - Cashback"],"description":"Credita (valor positivo) ou debita (valor negativo) créditos de um cliente. Motivo obrigatório — vira a descrição da transação. idempotency_key opcional (padrão Stripe): retry com a mesma chave não duplica o ajuste. Requer role owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","valor_centavos","motivo"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"valor_centavos":{"type":"integer"},"motivo":{"type":"string","minLength":3},"idempotency_key":{"type":"string","minLength":8,"maxLength":100}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creditos/dashboard":{"get":{"summary":"Dashboard de créditos do tenant (admin)","tags":["Apps - Cashback"],"description":"Agregados: emitido, resgatado, expirado, passivo em aberto, taxa de resgate e clientes com saldo. Emitido considera apenas lotes de cashback/vale_troca; resgatado soma TODOS os débitos do ledger, inclusive os que consumiram lotes de ajuste_manual — por isso taxa_resgate (resgatado/emitido) pode exceder 1.0. Requer role owner/manager.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creditos/public/saldo":{"get":{"summary":"Saldo de créditos do cliente logado","tags":["Apps - Cashback"],"description":"Retorna saldo disponível e pendente do cliente autenticado. Autenticação via x-user-id (JWT do cliente OTP).","responses":{"200":{"description":"Default Response"}}}},"/creditos/public/extrato":{"get":{"summary":"Extrato de créditos do cliente logado","tags":["Apps - Cashback"],"description":"Extrato paginado de transações de créditos do cliente autenticado. Autenticação via x-user-id (JWT do cliente OTP).","parameters":[{"schema":{"type":"integer","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","minimum":1,"maximum":100,"default":20},"in":"query","name":"pageSize","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/cashback/config":{"get":{"summary":"Ler configuração de cashback (admin)","tags":["Apps - Cashback"],"description":"Retorna configuração do app Cashback. Se não existe, retorna defaults sem criar (lazy). Requer role owner/manager.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Salvar configuração de cashback","tags":["Apps - Cashback"],"description":"Upsert da configuração do app Cashback. Ativar exige Programa de Fidelidade desativado (409 fidelidade_ativo).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"},"modo_earn":{"type":"string","enum":["global","categoria","valor"]},"percentual":{"type":"number"},"faixas":{"type":["array","null"]},"categorias_taxas":{"type":["array","null"]},"categorias_excluidas":{"type":"array","items":{"type":"string","format":"uuid"}},"base_earn":{"type":"string","enum":["produtos"]},"compra_minima_earn_centavos":{"type":"integer","minimum":0},"teto_earn_centavos":{"type":"integer","minimum":0},"excluir_promocionais":{"type":"boolean"},"earn_no_pdv":{"type":"boolean"},"carencia_dias":{"type":"integer"},"validade_dias":{"type":"integer"},"teto_uso_percentual":{"type":"number"},"compra_minima_uso_centavos":{"type":"integer","minimum":0},"cumulativo_com_cupom":{"type":"boolean"},"vale_troca_incentivo_percent":{"type":"number"},"recorrencia_ativa":{"type":"boolean"},"recorrencia_janela_dias":{"type":"integer","minimum":1},"recorrencia_faixas":{"type":["array","null"]}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/cashback/public/config":{"get":{"summary":"Configuração pública de cashback","tags":["Apps - Cashback"],"description":"Retorna apenas os campos públicos da config para o storefront. Sem autenticação.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators":{"get":{"summary":"Listar creators","tags":["Creators"],"description":"Lista os creators do tenant com métricas denormalizadas (GMV atribuído, pedidos, última venda).","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"q","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar creator","tags":["Creators"],"description":"Cadastra um creator com identidade fiscal completa. E-mail é a credencial do portal; documento é validado conforme o regime (PF/MEI usam CPF, Simples/Presumido usam CNPJ). Código do link e slug da vitrine são gerados automaticamente, únicos por tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","email","regime_fiscal","documento"],"properties":{"nome":{"type":"string","minLength":2,"maxLength":120},"email":{"type":"string"},"telefone":{"type":"string"},"regime_fiscal":{"type":"string","enum":["pf","mei","simples","presumido"]},"documento":{"type":"string"},"razao_social":{"type":"string"},"cliente_id":{"type":"string"},"handle_ig":{"type":"string"},"handle_tt":{"type":"string"},"handle_yt":{"type":"string"},"pix_tipo":{"type":"string","enum":["cpf","cnpj","email","telefone","aleatoria"]},"pix_chave":{"type":"string"},"forma_pagamento":{"type":"string","enum":["pix_manual","credito_loja"]},"status":{"type":"string"},"percentual_desconto_cupom":{"type":"number","minimum":0,"maximum":90}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/creators/candidatos":{"get":{"summary":"Clientes candidatos a creator","tags":["Creators"],"description":"Clientes recorrentes (2+ pedidos pagos em 180 dias) que ainda não são creators — a fonte de recrutamento mais barata e de melhor conversão.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/{id}":{"get":{"summary":"Detalhe do creator","tags":["Creators"],"description":"Cadastro completo de um creator para a tela de edição, incluindo documento e chave Pix (a listagem não traz dado fiscal).","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar creator","tags":["Creators"],"description":"Atualiza campos permitidos (whitelist). Código e slug não mudam por aqui: o código é o identificador falado em vídeo. Sair do status ativo desliga o cupom nominal do creator; voltar para ativo religa o cupom com o código dele.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/{id}/descongelar":{"patch":{"summary":"Descongelar creator","tags":["Creators"],"description":"Limpa o congelamento por taxa de devolução (congelado_em e congelado_motivo). O creator volta a entrar nos próximos lotes de pagamento.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/{id}/cupom":{"post":{"summary":"Criar cupom nominal do creator","tags":["Creators"],"description":"Cria a promoção-cupom vinculada ao creator (o código que ele fala no vídeo). Percentual de desconto é opcional — código de creator atribui e PODE dar desconto; sem desconto, o cupom vira só identificador de atribuição.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"percentual_desconto":{"type":"number","minimum":0,"maximum":90},"uso_por_cliente":{"type":"integer","minimum":1}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/creators/rate-card":{"get":{"summary":"Listar regras de comissão (vigências)","tags":["Creators"],"description":"Retorna as vigências vivas do rate card: cada linha vem com vigencia (vigente ou agendada) e encerra_em (fim agendado, quando houver). Versões já substituídas ficam de fora; a cadeia completa vive no banco como histórico do contrato.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar regra de comissão","tags":["Creators"],"description":"Regra por especificidade: produto > categoria > creator > tier > geral. bps de 0 a 8000 (0% a 80%). bps_midia_paga é a taxa reduzida quando a venda veio de anúncio pago do lojista. Fora do modo sombra, linha nova que reduz a taxa efetiva que hoje vence por especificidade para o mesmo alvo nasce agendada para +30 dias (aplicacao: agendada_30_dias no response); melhora ou dimensão sem regra vigente vale na hora.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["bps"],"properties":{"bps":{"type":"integer","minimum":0,"maximum":8000},"bps_midia_paga":{"type":"integer","minimum":0,"maximum":8000},"taxa_cliente_novo_bps":{"type":"integer","minimum":0,"maximum":8000},"teto_margem_bps":{"type":"integer","minimum":1,"maximum":10000},"teto_pedido_centavos":{"type":"integer","minimum":1},"creator_id":{"type":"string"},"produto_id":{"type":"string"},"categoria_id":{"type":"string"},"tier_slug":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/creators/rate-card/{id}":{"patch":{"summary":"Atualizar regra de comissão (contrato versionado)","tags":["Creators"],"description":"Mudança vira LINHA NOVA na cadeia de vigências e a linha atual ganha substituida_em. Aumento ou ajuste vale na hora; redução de taxa fora do modo sombra é agendada para +30 dias (a taxa atual segue valendo até lá). ativo: false encerra a regra com a mesma trava; ativo: true cancela um encerramento agendado.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Encerrar regra de comissão","tags":["Creators"],"description":"Encerrar não zera a taxa na hora: fora do modo sombra o fim é agendado para +30 dias (substituida_em futuro, sem linha nova) e a taxa segue valendo até lá. Em modo sombra o fim é imediato. Encerrar uma linha ainda agendada apenas cancela a mudança.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/comissoes":{"get":{"summary":"Extrato de comissões","tags":["Creators"],"description":"Linha a linha, com motivo da atribuição, trava aplicada e status. É o mesmo dado que o creator vê no extrato dele — os dois lados fecham no centavo.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"creator_id","required":false},{"schema":{"type":"integer","minimum":1,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/painel":{"get":{"summary":"Painel do canal","tags":["Creators"],"description":"Agregados do canal de creators: GMV atribuído, comissão por status, e o número que vende o app — quanto NÃO saiu do caixa por devolução.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/payouts":{"get":{"summary":"Listar lotes de pagamento","tags":["Creators"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/payouts/csv":{"get":{"summary":"Exportar payouts em CSV","tags":["Creators"],"description":"Exporta os lotes de pagamento em CSV pronto para Excel BR: BOM UTF-8, separador ponto e vírgula, valores com vírgula decimal. status aceita pendente (padrão, lotes abertos), aberto, pago ou cancelado.","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/payouts/gerar":{"post":{"summary":"Gerar lotes de pagamento","tags":["Creators"],"description":"Agrupa as comissões liberadas e ainda sem lote em um lote aberto por creator, com snapshot da chave Pix validada. Comissões em modo sombra não entram. Creator pix_manual com chave ausente ou inválida, congelado ou em revisão fica fora do lote e volta no array ignorados; creator com taxa de devolução alta (sem congelamento automático) entra no lote e volta em alertas. No lote manual o mínimo de valor não bloqueia.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/creators/payouts/{id}/pagar":{"post":{"summary":"Confirmar pagamento de um lote","tags":["Creators"],"description":"pix_manual: o lojista pagou pelo banco dele e confirma aqui (comprovante opcional). credito_loja: credita na conta-cliente do creator pelo ledger de créditos, com idempotência. As comissões do lote viram pagas.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"comprovante_url":{"type":"string"},"observacao":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/payouts/{id}/nota":{"patch":{"summary":"Conferir ou dispensar a nota fiscal de um lote","tags":["Creators"],"description":"conferida: o lojista validou manualmente a nota anexada pelo creator no portal. dispensada: dispensa consciente da exigência para este lote (fica registrado quem dispensou). O upload da nota é feito pelo creator no portal dele.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nota_status"],"properties":{"nota_status":{"type":"string","enum":["conferida","dispensada"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/payouts/{id}/nota-url":{"get":{"summary":"Gerar URL de visualização da nota fiscal de um lote","tags":["Creators"],"description":"Gera signed URL (5 min) para o lojista visualizar a nota fiscal anexada pelo creator no bucket privado kyc-docs.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}}}}},"/creators/payouts/{id}/cancelar":{"post":{"summary":"Cancelar um lote aberto","tags":["Creators"],"description":"Desfaz o agrupamento: as comissões voltam a ficar liberadas sem lote e podem entrar num lote futuro.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me":{"get":{"summary":"Perfil e saldos do creator","tags":["Creators - Portal"],"description":"Retorna o perfil do creator autenticado (OTP da loja) com os saldos: no Cofre, liberado, pago e estornado. Nunca expõe dados de compradores.","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/extrato":{"get":{"summary":"Extrato do creator","tags":["Creators - Portal"],"description":"Linha a linha: pedido, motivo da atribuição, valor, status e data prevista de liberação. O comprador nunca é exposto.","parameters":[{"schema":{"type":"integer","minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","minimum":0},"in":"query","name":"offset","required":false},{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/pagamentos":{"get":{"summary":"Pagamentos do creator","tags":["Creators - Portal"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/recebimento":{"patch":{"summary":"Atualizar chave Pix e forma de recebimento","tags":["Creators - Portal"],"description":"O creator informa e atualiza a própria chave Pix e escolhe entre receber por Pix ou em crédito da loja.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pix_tipo":{"type":"string","enum":["cpf","cnpj","email","telefone","aleatoria"]},"pix_chave":{"type":"string"},"forma_pagamento":{"type":"string","enum":["pix_manual","credito_loja"]}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/vitrine/{slug}":{"get":{"summary":"Vitrine pública do creator","tags":["Creators - Portal"],"description":"Página pública do creator na loja: identidade, cupom nominal ativo, reels e produtos para montar cards com o link de atribuição (?rkt_c=codigo). LGPD: nunca expõe dados fiscais ou Pix. 404 para slug inexistente ou creator não ativo.","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/payouts/{id}/nota-upload-url":{"post":{"summary":"Gerar URL de upload da nota fiscal","tags":["Creators - Portal"],"description":"Gera signed upload URL no bucket privado de documentos para o creator subir a nota fiscal do lote. Só para payout do próprio creator com nota pendente ou enviada (reenvio antes da conferência).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["extensao"],"properties":{"extensao":{"type":"string","enum":["pdf","xml","png","jpg","jpeg","webp"]}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/payouts/{id}/nota":{"post":{"summary":"Anexar nota fiscal a um pagamento","tags":["Creators - Portal"],"description":"O creator registra a URL (ou path do storage) da nota fiscal do lote. Funciona no payout do próprio creator com nota_status pendente ou enviada (reenvio substitui a nota antes da conferência); grava nota_fiscal_url, nota_fiscal_enviada_em e muda nota_status para enviada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","minLength":5,"maxLength":2048}}}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true},{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/contrato":{"get":{"summary":"Regras vigentes do programa (contrato do creator)","tags":["Creators - Portal"],"description":"As regras do programa publicadas na tela, não enterradas nos termos: precedência de atribuição e janelas, rate card vigente e agendado do creator, tetos, congelamento por devolução, forma de pagamento e mínimo de lote. Inclui versão derivada para o portal exibir \"contrato atualizado em\".","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators-public/{sub}/me/amostras":{"get":{"summary":"Amostras reembolsáveis do creator","tags":["Creators - Portal"],"description":"Lista as amostras do creator com status e quanto falta para a meta. A checagem de cumprimento/expiração roda aqui (lazy, sem cron).","parameters":[{"schema":{"type":"string"},"in":"path","name":"sub","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/creators/amostras":{"post":{"summary":"Vincular pedido pago como amostra reembolsável","tags":["Creators"],"description":"O lojista vincula um pedido pago do próprio creator como amostra, com meta de vendas atribuídas (centavos) e prazo em dias. O pedido precisa ser do comprador vinculado ao creator.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["creator_id","pedido_id","meta_vendas_centavos","prazo_dias"],"properties":{"creator_id":{"type":"string"},"pedido_id":{"type":"string"},"meta_vendas_centavos":{"type":"integer","minimum":1},"prazo_dias":{"type":"integer","minimum":1,"maximum":365},"observacao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Listar amostras reembolsáveis","tags":["Creators"],"description":"Lista as amostras do tenant com progresso da meta. A checagem de cumprimento/expiração roda aqui (lazy, sem cron).","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"creator_id","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/creators/amostras/{id}":{"delete":{"summary":"Cancelar uma amostra","tags":["Creators"],"description":"Cancela uma amostra ativa. O pedido volta a ser um pedido comum, sem meta.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/config":{"get":{"summary":"Ler configuração de assinaturas","tags":["Apps - Assinaturas"],"description":"Retorna configuração do app de assinaturas. Se não existe, retorna defaults (lazy creation).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Salvar configuração de assinaturas","tags":["Apps - Assinaturas"],"description":"Upsert da configuração (ativo, desconto, frequências, lembrete, retentativas).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"},"desconto_percentual":{"type":"number"},"frequencias_disponiveis":{"type":"array","items":{"type":"string"}},"lembrete_dias_antes":{"type":"integer"},"max_retentativas_pagamento":{"type":"integer"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/planos":{"get":{"summary":"Listar planos de assinatura","tags":["Apps - Assinaturas"],"description":"Retorna planos do tenant com produtos vinculados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"post":{"summary":"Criar plano de assinatura","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","desconto_percentual","frequencias"],"properties":{"nome":{"type":"string"},"desconto_percentual":{"type":"number"},"frequencias":{"type":"array","items":{"type":"string"}},"produto_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/planos/{id}":{"get":{"summary":"Detalhe do plano de assinatura","tags":["Apps - Assinaturas"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar plano de assinatura","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"desconto_percentual":{"type":"number"},"frequencias":{"type":"array","items":{"type":"string"}},"ativo":{"type":"boolean"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar plano de assinatura","tags":["Apps - Assinaturas"],"description":"Soft delete (ativo = false).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/planos/{id}/produtos":{"post":{"summary":"Associar produtos ao plano","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_ids"],"properties":{"produto_ids":{"type":"array","items":{"type":"string","format":"uuid"}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/planos/{id}/produtos/{produtoId}":{"delete":{"summary":"Remover produto do plano","tags":["Apps - Assinaturas"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas":{"get":{"summary":"Listar assinaturas (admin)","tags":["Apps - Assinaturas"],"description":"Listagem paginada de assinaturas com filtro por status e itens vinculados.","parameters":[{"schema":{"type":"string","enum":["ativa","pausada","cancelada","erro_pagamento"]},"in":"query","name":"status","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/dashboard":{"get":{"summary":"Dashboard de assinaturas","tags":["Apps - Assinaturas"],"description":"KPIs: ativas, pausadas, canceladas, erro_pagamento, total renovações, MRR estimado e churn 30d.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/{id}":{"get":{"summary":"Detalhe da assinatura (admin)","tags":["Apps - Assinaturas"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/{id}/renovacoes":{"get":{"summary":"Listar renovações da assinatura","tags":["Apps - Assinaturas"],"parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"limit","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/{id}/admin/pausar":{"post":{"summary":"Pausar assinatura (admin)","tags":["Apps - Assinaturas"],"description":"Pausa uma assinatura ativa. Envia email de notificação.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/{id}/admin/cancelar":{"post":{"summary":"Cancelar assinatura (admin)","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/{id}/admin/reativar":{"post":{"summary":"Reativar assinatura (admin)","tags":["Apps - Assinaturas"],"description":"Reativa assinatura pausada ou com erro de pagamento. Recalcula próximo pedido.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/config":{"get":{"summary":"Config pública de assinaturas","tags":["Apps - Assinaturas"],"description":"Retorna se assinaturas estão ativas, desconto e frequências para o storefront.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/produto/{produtoId}/config":{"get":{"summary":"Config de assinatura do produto","tags":["Apps - Assinaturas"],"description":"Resolve config com herança: produto > plano > config global. Retorna frequências e descontos aplicáveis.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/produto/{produtoId}/planos":{"get":{"summary":"Planos ativos do produto (PDP)","tags":["Apps - Assinaturas"],"description":"Retorna planos de assinatura ativos que incluem este produto. Usado pela PDP.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/criar":{"post":{"summary":"Criar assinatura (cliente)","tags":["Apps - Assinaturas"],"description":"Cliente cria assinatura com frequência, itens e desconto. Valida config ativa, frequência e produtos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","cliente_id","frequencia","itens"],"properties":{"account_id":{"type":"string","format":"uuid"},"cliente_id":{"type":"string","format":"uuid"},"frequencia":{"type":"string"},"itens":{"type":"array","items":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variante":{"type":"string"},"quantidade":{"type":"integer","default":1}}}},"endereco_entrega_id":{"type":"string","format":"uuid"},"metodo_pagamento_token":{"type":"string"},"plano_id":{"type":"string","format":"uuid"}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/minhas":{"get":{"summary":"Minhas assinaturas (cliente)","tags":["Apps - Assinaturas"],"description":"Lista assinaturas do cliente com itens e produtos.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"cliente_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/pausar":{"post":{"summary":"Pausar assinatura (cliente)","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id"],"properties":{"cliente_id":{"type":"string","format":"uuid"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/reativar":{"post":{"summary":"Reativar assinatura (cliente)","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id"],"properties":{"cliente_id":{"type":"string","format":"uuid"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/cancelar":{"post":{"summary":"Cancelar assinatura (cliente)","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/pular":{"post":{"summary":"Pular próxima renovação","tags":["Apps - Assinaturas"],"description":"Adia o próximo pedido em 1 ciclo da frequência.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id"],"properties":{"cliente_id":{"type":"string","format":"uuid"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/itens":{"put":{"summary":"Atualizar itens da assinatura","tags":["Apps - Assinaturas"],"description":"Substitui itens da assinatura. Estratégia segura: INSERT novos primeiro, DELETE antigos só se INSERT OK.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","itens"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"itens":{"type":"array","items":{"type":"object","required":["produto_id"],"properties":{"produto_id":{"type":"string","format":"uuid"},"variante":{"type":"string"},"quantidade":{"type":"integer","default":1}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/cartao":{"put":{"summary":"Atualizar cartão da assinatura","tags":["Apps - Assinaturas"],"description":"Atualiza token de pagamento. Se estava em erro_pagamento, reativa automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","metodo_pagamento_token"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"metodo_pagamento_token":{"type":"string"},"metodo_pagamento_ultimos4":{"type":"string"},"metodo_pagamento_bandeira":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/endereco":{"put":{"summary":"Alterar endereço de entrega","tags":["Apps - Assinaturas"],"description":"Cliente altera endereço de entrega. Valida que o endereço pertence ao cliente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","endereco_entrega_id"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"endereco_entrega_id":{"type":"string","format":"uuid"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/assinaturas/public/{id}/frequencia":{"put":{"summary":"Alterar frequência da assinatura","tags":["Apps - Assinaturas"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cliente_id","frequencia"],"properties":{"cliente_id":{"type":"string","format":"uuid"},"frequencia":{"type":"string","enum":["semanal","quinzenal","mensal","bimestral","trimestral","semestral"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/lotes":{"get":{"summary":"Listar lotes de um produto","tags":["Catálogo - Lotes"],"description":"Retorna lotes do produto ordenados por data de validade (FIFO). Usado para rastreabilidade e controle de vencimento.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true,"description":"ID do produto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"post":{"summary":"Criar lote","tags":["Catálogo - Lotes"],"description":"Cria um novo lote para um produto. Retorna 409 se já existir lote com o mesmo código para o produto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","codigo_lote","quantidade"],"properties":{"produto_id":{"type":"string","format":"uuid","description":"ID do produto"},"variacao_id":{"type":["string","null"],"format":"uuid","description":"Variação do produto (opcional)"},"local_id":{"type":["string","null"],"format":"uuid","description":"CD/local onde o lote está (opcional — default: principal)"},"codigo_lote":{"type":"string","description":"Código identificador do lote"},"quantidade":{"type":"integer","minimum":0,"maximum":1000000,"description":"Quantidade no lote"},"data_fabricacao":{"type":["string","null"],"format":"date","description":"Data de fabricação (YYYY-MM-DD)"},"data_validade":{"type":["string","null"],"format":"date","description":"Data de validade (YYYY-MM-DD)"},"custo_unitario_centavos":{"type":["integer","null"],"description":"Custo unitário em centavos"},"fornecedor":{"type":["string","null"],"description":"Nome do fornecedor"},"observacoes":{"type":["string","null"],"description":"Observações livres"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/lotes/{id}":{"put":{"summary":"Atualizar lote","tags":["Catálogo - Lotes"],"description":"Atualiza campos de um lote existente. Quantidade não pode ser negativa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"quantidade":{"type":"integer","minimum":0,"maximum":1000000,"description":"Nova quantidade"},"data_fabricacao":{"type":["string","null"],"format":"date"},"data_validade":{"type":["string","null"],"format":"date"},"custo_unitario_centavos":{"type":["integer","null"]},"fornecedor":{"type":["string","null"]},"observacoes":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do lote"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir lote zerado","tags":["Catálogo - Lotes"],"description":"Remove um lote. Falha com 422 se o lote ainda tiver estoque (deve zerar antes de excluir).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do lote"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluído com sucesso"},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}}}},"/lotes/vencendo":{"get":{"summary":"Lotes próximos do vencimento","tags":["Catálogo - Lotes"],"description":"Retorna lotes com estoque que vencem nos próximos N dias, categorizados como vencido/crítico/alerta. Ideal para widget de dashboard.","parameters":[{"schema":{"type":"integer","default":30,"minimum":1,"maximum":365},"in":"query","name":"dias","required":false,"description":"Janela de dias para verificar vencimento"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"resumo":{"type":"object","properties":{"vencidos":{"type":"integer"},"criticos":{"type":"integer"},"alerta":{"type":"integer"},"total":{"type":"integer"}}}}}}}}}}},"/lotes/relatorio":{"get":{"summary":"Relatório de lotes com filtros","tags":["Catálogo - Lotes"],"description":"Relatório paginado de lotes próximos ao vencimento. Enriquecido com nome/SKU do produto e status (vencido/crítico/alerta). Filtrável por categoria.","parameters":[{"schema":{"type":"integer","default":30},"in":"query","name":"dias","required":false,"description":"Janela de vencimento em dias"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"categoria_id","required":false,"description":"Filtrar por categoria"},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false,"description":"Página"},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"page_size","required":false,"description":"Itens por página (máx 50)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"page":{"type":"integer"},"page_size":{"type":"integer"},"total":{"type":"integer"},"total_pages":{"type":"integer"}}}}}}}}}}},"/lotes/movimentacoes":{"get":{"summary":"Movimentações de lote (rastreabilidade)","tags":["Catálogo - Lotes"],"description":"Ledger de baixas/reposições por lote. Filtre por produto, lote ou pedido para recall/auditoria — mostra qual pedido levou qual lote.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"lote_id","required":false},{"schema":{"type":"string"},"in":"query","name":"codigo_lote","required":false,"description":"Filtra pelo código do lote (recall)"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"pedido_id","required":false},{"schema":{"type":"integer","default":100,"maximum":500},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/etiqueta-modelos":{"get":{"summary":"Listar modelos de etiqueta","tags":["Catálogo - Etiquetas"],"description":"Retorna os modelos de etiqueta cadastrados pelo tenant, mais recentes primeiro.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"modelos":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"post":{"summary":"Criar modelo de etiqueta","tags":["Catálogo - Etiquetas"],"description":"Cadastra um novo modelo de etiqueta (dimensões em mm + campos habilitados no layout).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","largura_mm","altura_mm"],"properties":{"nome":{"type":"string","minLength":1,"description":"Nome do modelo (ex: Padrão 50x30)"},"largura_mm":{"type":"number","minimum":10,"maximum":210,"description":"Largura em mm"},"altura_mm":{"type":"number","minimum":10,"maximum":210,"description":"Altura em mm"},"campos":{"type":"object","additionalProperties":true,"description":"Campos habilitados no layout (ex: nome, preco, codigo_barras, data_matrix, lote, fabricacao, validade)"},"formato":{"type":"string","enum":["termica","folha"],"description":"Formato do modelo: termica (rolo/impressora térmica) ou folha (folha A4/carta com grid de etiquetas)"},"folha":{"type":"object","additionalProperties":true,"nullable":true,"description":"Configuração de grid da folha (colunas, linhas, margens, espaçamento) quando formato=folha"},"elementos":{"type":"array","items":{"type":"object","additionalProperties":true},"nullable":true,"description":"Elementos posicionados livremente no layout da etiqueta (texto, código de barras, imagem, etc.)"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/etiqueta-modelos/{id}":{"put":{"summary":"Editar modelo de etiqueta","tags":["Catálogo - Etiquetas"],"description":"Atualiza campos de um modelo de etiqueta existente do tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"largura_mm":{"type":"number","minimum":10,"maximum":210},"altura_mm":{"type":"number","minimum":10,"maximum":210},"campos":{"type":"object","additionalProperties":true,"description":"Campos habilitados no layout (ex: nome, preco, codigo_barras, data_matrix, lote, fabricacao, validade)"},"formato":{"type":"string","enum":["termica","folha"],"description":"Formato do modelo: termica (rolo/impressora térmica) ou folha (folha A4/carta com grid de etiquetas)"},"folha":{"type":"object","additionalProperties":true,"nullable":true,"description":"Configuração de grid da folha (colunas, linhas, margens, espaçamento) quando formato=folha"},"elementos":{"type":"array","items":{"type":"object","additionalProperties":true},"nullable":true,"description":"Elementos posicionados livremente no layout da etiqueta (texto, código de barras, imagem, etc.)"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do modelo de etiqueta"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Remover modelo de etiqueta","tags":["Catálogo - Etiquetas"],"description":"Remove permanentemente um modelo de etiqueta do tenant.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID do modelo de etiqueta"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Removido com sucesso"}}}},"/custom-fields":{"get":{"summary":"Listar definições de campos customizados","tags":["Catálogo - Campos Customizados"],"description":"Retorna definições de campos do tenant. Suporta herança descendente: se categoria_id for informado, retorna campos globais + da categoria + dos ancestrais.","parameters":[{"schema":{"type":"string","default":"produto"},"in":"query","name":"entidade","required":false,"description":"Tipo de entidade (ex: produto)"},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"categoria_id","required":false,"description":"ID da categoria para herança descendente"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"post":{"summary":"Criar campo customizado","tags":["Catálogo - Campos Customizados"],"description":"Cria uma definição de campo customizado. Slug é auto-gerado se não informado. Tipos select/multi_select exigem opcoes.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","tipo"],"properties":{"nome":{"type":"string","description":"Nome do campo"},"slug":{"type":"string","description":"Slug (auto-gerado se não informado)"},"tipo":{"type":"string","enum":["texto","numero","booleano","data","select","multi_select","url","cor","rich_text","arquivo","tabela","dimensoes"],"description":"Tipo de dado"},"entidade":{"type":"string","default":"produto","description":"Entidade alvo"},"opcoes":{"type":"array","items":{"type":"string"},"description":"Opções (obrigatório para select/multi_select)"},"obrigatorio":{"type":"boolean","default":false},"visivel_loja":{"type":"boolean","default":true,"description":"Exibir na ficha técnica pública"},"grupo":{"type":["string","null"],"description":"Agrupamento visual (ex: Ficha técnica)"},"ordem":{"type":"integer","default":0},"categoria_id":{"type":["string","null"],"format":"uuid","description":"Escopo por categoria (null = global)"},"marca_filter":{"type":["string","null"],"description":"Filtro por marca"},"tags_filter":{"type":"array","items":{"type":"string"},"description":"Filtro por tags"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/custom-fields/{id}":{"put":{"summary":"Atualizar campo customizado","tags":["Catálogo - Campos Customizados"],"description":"Atualiza definição de um campo customizado existente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"},"slug":{"type":"string"},"tipo":{"type":"string"},"opcoes":{"type":"array","items":{"type":"string"}},"obrigatorio":{"type":"boolean"},"visivel_loja":{"type":"boolean"},"grupo":{"type":["string","null"]},"ordem":{"type":"integer"},"categoria_id":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da definição"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"409":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}},"delete":{"summary":"Excluir campo customizado","tags":["Catálogo - Campos Customizados"],"description":"Remove definição e todos os valores associados (cascade).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true,"description":"ID da definição"}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Excluído com sucesso"}}}},"/custom-fields/reorder":{"put":{"summary":"Reordenar campos customizados","tags":["Catálogo - Campos Customizados"],"description":"Atualiza a ordem de exibição das definições de campos em batch.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"type":"object","required":["id","ordem"],"properties":{"id":{"type":"string","format":"uuid"},"ordem":{"type":"integer"}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/custom-fields/values/{entidade_id}":{"get":{"summary":"Obter valores de campos de uma entidade","tags":["Catálogo - Campos Customizados"],"description":"Retorna os valores preenchidos dos campos customizados para uma entidade específica (ex: produto), com detalhes da definição.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"entidade_id","required":true,"description":"ID da entidade (ex: ID do produto)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}},"put":{"summary":"Salvar valores de campos em massa","tags":["Catálogo - Campos Customizados"],"description":"Upsert de valores de campos customizados para uma entidade. Se values vazio, limpa todos os valores.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["values"],"properties":{"values":{"type":"array","items":{"type":"object","required":["field_definition_id"],"properties":{"field_definition_id":{"type":"string","format":"uuid"},"valor_texto":{"type":["string","null"]},"valor_numero":{"type":["number","null"]},"valor_booleano":{"type":["boolean","null"]},"valor_data":{"type":["string","null"],"format":"date"},"valor_json":{}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"entidade_id","required":true,"description":"ID da entidade (ex: ID do produto)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/custom-fields/public/{produto_id}":{"get":{"summary":"Ficha técnica pública do produto","tags":["Catálogo - Campos Customizados"],"description":"Retorna campos customizados visíveis na loja para um produto. Rota pública (sem JWT). Filtra por visivel_loja, categoria, marca e tags do produto.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true,"description":"ID do tenant"},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produto_id","required":true,"description":"ID do produto"}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"nome":{"type":"string"},"slug":{"type":"string"},"tipo":{"type":"string"},"grupo":{"type":["null","string"]},"valor":{"type":"string"}}}}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/custom-fields/seeds/{vertical}":{"get":{"summary":"Sugestões de campos por vertical","tags":["Catálogo - Campos Customizados"],"description":"Retorna campos sugeridos para a vertical (ex: pet, varejo, saude, servicos). Não cria nada no banco.","parameters":[{"schema":{"type":"string"},"in":"path","name":"vertical","required":true,"description":"Vertical (pet, varejo, saude, servicos)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}}}},"/custom-fields/seeds/apply":{"post":{"summary":"Aplicar campos sugeridos da vertical","tags":["Catálogo - Campos Customizados"],"description":"Cria definições de campos customizados a partir do seed da vertical. Pula campos com slug já existente (idempotente).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["vertical"],"properties":{"vertical":{"type":"string","description":"Vertical (pet, varejo, saude, servicos)"},"entidade":{"type":"string","default":"produto"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"criados":{"type":"integer"}}}}}},"400":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/custom-fields/marcas-autocomplete":{"get":{"summary":"Autocomplete de marcas","tags":["Catálogo - Campos Customizados"],"description":"Retorna marcas distintas dos produtos do tenant para autocomplete no filtro de campos customizados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}}}}}}}}},"/custom-fields/tags-autocomplete":{"get":{"summary":"Autocomplete de tags","tags":["Catálogo - Campos Customizados"],"description":"Retorna tags distintas dos produtos do tenant para autocomplete no filtro de campos customizados.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"}}}}}}}}}},"/gift-wrap/config":{"get":{"summary":"Ler configuração de embalagem presente (admin)","tags":["Apps - Embalagem Presente"],"description":"Retorna a configuração efetiva do gift wrap (mesma fonte que o storefront e o pedido usam: tenant_apps.config_global). Se o app não está instalado nem ativo, retorna defaults com ativo: false.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Salvar configuração de embalagem presente (legado)","tags":["Apps - Embalagem Presente"],"description":"LEGADO — grava na tabela gift_wrap_config, que hoje só serve de fallback. A fonte canônica é tenant_apps.config_global (app_id=embalagem-presente), gravada pela tela do app. Para tenant com o app instalado, este endpoint não afeta storefront nem pedido.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ativo":{"type":"boolean"},"preco_centavos":{"type":"integer","minimum":0},"permite_mensagem":{"type":"boolean"},"max_caracteres":{"type":"integer","minimum":0,"maximum":1000},"label_checkout":{"type":"string","maxLength":100}}}}}},"deprecated":true,"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/gift-wrap/config":{"get":{"summary":"Config pública de embalagem presente","tags":["Apps - Embalagem Presente"],"description":"Retorna a config do gift wrap para o storefront, resolvida de tenant_apps.config_global (app_id=embalagem-presente) com fallback legado. Se não ativo, retorna o mesmo shape com ativo: false.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ativo":{"type":"boolean"},"preco_centavos":{"type":"integer"},"permite_mensagem":{"type":"boolean"},"max_caracteres":{"type":"integer"},"label_checkout":{"type":"string"}}}}}}}}},"/public/gift-wrap/item":{"post":{"summary":"Marcar/desmarcar embalagem presente em um item do carrinho","tags":["Apps - Embalagem Presente"],"description":"Grava a escolha de presente na linha do rascunho da sessão (dados_extras.gift_wrap) e recalcula os totais. Cobrança é POR UNIDADE (quantidade × preço). O preço nunca vem do cliente: é sempre resolvido no servidor. App inativo ⇒ 422 gift_wrap_indisponivel. Retorna o carrinho no shape do GET /cart. Endpoint público (sem JWT).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["account_id","session_token","item_id","ativo"],"properties":{"account_id":{"type":"string","format":"uuid"},"session_token":{"type":"string"},"item_id":{"type":"string","format":"uuid"},"ativo":{"type":"boolean"},"mensagem":{"type":"string","nullable":true}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/gift-wrap/metricas":{"get":{"summary":"Métricas de embalagem presente","tags":["Apps - Embalagem Presente"],"description":"Retorna total de pedidos, pedidos com presente, percentual de adoção, receita extra e itens marcados no carrinho. Default: últimos 30 dias.","parameters":[{"schema":{"type":"string","format":"date-time"},"in":"query","name":"desde","required":false,"description":"Data início (default: 30 dias atrás)"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"total_pedidos":{"type":"integer"},"pedidos_com_presente":{"type":"integer"},"percentual":{"type":"number"},"receita_extra_centavos":{"type":"integer"},"itens_marcados":{"type":"integer"}}}}}}}}},"/devolucoes":{"get":{"summary":"Listar devoluções","tags":["OMS - Devoluções"],"description":"Lista devoluções do tenant com filtros por status, tipo e busca textual. Paginação via page/page_size.","parameters":[{"schema":{"type":"string","enum":["solicitada","aprovada","recusada","etiqueta_gerada","em_transito","recebida","recebida_balcao","reembolsada"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","enum":["devolucao","troca"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","enum":["loja","pdv","admin","canal"]},"in":"query","name":"origem","required":false},{"schema":{"type":"string"},"in":"query","name":"busca","required":false,"description":"Busca por número ou motivo"},{"schema":{"type":"string","default":"1"},"in":"query","name":"page","required":false},{"schema":{"type":"string","default":"25"},"in":"query","name":"page_size","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}}},"/devolucoes/{id}":{"get":{"summary":"Detalhe da devolução","tags":["OMS - Devoluções"],"description":"Retorna devolução completa com pedido, itens (com dados do pedido_item original), e timeline de status.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/devolucoes/{id}/aprovar":{"post":{"summary":"Aprovar devolução","tags":["OMS - Devoluções"],"description":"Aprova uma devolução solicitada, transitando o status para aprovada.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/devolucoes/{id}/recusar":{"post":{"summary":"Recusar devolução","tags":["OMS - Devoluções"],"description":"Recusa uma devolução com motivo obrigatório. Transita o status para recusada.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string"}},"required":["motivo"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/devolucoes/{id}/gerar-etiqueta":{"post":{"summary":"Gerar etiqueta reversa (Melhor Envio)","tags":["OMS - Devoluções"],"description":"Gera etiqueta reversa no Melhor Envio para o cliente devolver o produto. A devolução precisa estar aprovada. Requer conta Melhor Envio conectada e local de estoque cadastrado.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"sucesso":{"type":"boolean"},"tracking":{"type":"string"},"pdf_url":{"type":"string"},"shipment_id":{"type":"string"}}}}}}}}},"/devolucoes/{id}/confirmar-recebimento":{"post":{"summary":"Confirmar recebimento do produto devolvido","tags":["OMS - Devoluções"],"description":"Confirma que o produto devolvido foi recebido pela loja. Aceita transição de etiqueta_gerada ou em_transito para recebida.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"observacao":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/devolucoes/{id}/reembolsar":{"post":{"summary":"Processar reembolso da devolução","tags":["OMS - Devoluções"],"description":"Processa o reembolso da devolução. A devolução precisa estar com status recebida. Métodos: estorno_cartao, credito_loja ou pix.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"metodo":{"type":"string","enum":["estorno_cartao","credito_loja","pix"]}},"required":["metodo"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/devolucoes":{"post":{"summary":"Solicitar devolução (cliente)","tags":["OMS - Devoluções"],"description":"Cliente solicita devolução ou troca de um pedido entregue. Valida identidade por email, verifica prazo CDC (Art. 49 - auto-aprovação dentro de 7 dias), e valida itens/quantidades. Rate-limited: 5 req/min. Endpoint público (sem JWT).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pedido_id":{"type":"string","format":"uuid"},"account_id":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"tipo":{"type":"string","enum":["devolucao","troca"]},"motivo":{"type":"string","enum":["arrependimento","defeito","produto_errado","produto_diferente_da_foto","tamanho_errado","nao_gostei","outro"]},"motivo_detalhe":{"type":"string","nullable":true},"metodo_reembolso":{"type":"string","enum":["estorno_cartao","credito_loja","pix"],"nullable":true,"description":"Preferência de reembolso escolhida pelo cliente no wizard. O lojista pode ajustar ao processar."},"itens":{"type":"array","items":{"type":"object","properties":{"pedido_item_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer","minimum":1},"motivo":{"type":"string","nullable":true},"tamanho_feedback":{"type":"string","enum":["pequeno","grande"],"nullable":true,"description":"Quando o motivo é tamanho_errado: a peça ficou pequena ou grande. Alimenta o viés de modelagem do Provador Virtual (view provador_sinais_modelagem)."}},"required":["pedido_item_id","quantidade"]},"minItems":1}},"required":["pedido_id","account_id","email","motivo","itens"]}}},"required":true},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/devolucoes/opcoes":{"get":{"summary":"Opções de reembolso da devolução (cliente)","tags":["OMS - Devoluções"],"description":"Retorna os métodos de reembolso disponíveis para o pedido, o incentivo de vale-troca configurado pelo lojista e a situação do prazo CDC. Usado pelo wizard de devolução do storefront antes de enviar a solicitação. Rate-limited: 15 req/min. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"pedido_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/devolucoes/por-cliente":{"get":{"summary":"Listar devoluções do cliente (por email)","tags":["OMS - Devoluções"],"description":"Lista todas as devoluções dos pedidos do cliente no tenant, validando identidade por email. Usado pela aba Devoluções da Minha Conta. Rate-limited: 15 req/min. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":true},{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/public/devolucoes/por-pedido/{pedidoId}":{"get":{"summary":"Listar devoluções de um pedido (cliente)","tags":["OMS - Devoluções"],"description":"Lista todas as devoluções de um pedido, validando identidade por email. Usado pela aba Devoluções da Minha Conta. Rate-limited: 15 req/min. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}}},"/public/devolucoes/{id}":{"get":{"summary":"Acompanhar devolução (cliente)","tags":["OMS - Devoluções"],"description":"Cliente acompanha o status da devolução. Requer email para validação de identidade. Retorna timeline, etiqueta reversa e dados dos itens. Rate-limited: 15 req/min. Endpoint público (sem JWT).","parameters":[{"schema":{"type":"string","format":"email"},"in":"query","name":"email","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/onboarding/public/{token}":{"get":{"summary":"Buscar onboarding pelo token (público)","tags":["Onboarding"],"description":"Retorna dados do onboarding pelo token. Acesso público para o formulário de briefing do cliente.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Atualizar dados do onboarding (autosave)","tags":["Onboarding"],"description":"Autosave do formulário de briefing. Calcula fases completas automaticamente. Só permite update em status draft.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/public/{token}/submit":{"post":{"summary":"Submeter briefing de onboarding","tags":["Onboarding"],"description":"Valida fases obrigatórias (1 e 3) e muda status para submitted. Dispara provisionamento automático em background (submitted -> processing -> review).","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/public/{token}/upload":{"post":{"summary":"Upload de arquivo (planilha ou foto)","tags":["Onboarding"],"description":"Faz upload de arquivo para o bucket onboarding-files do Supabase Storage. Requer @fastify/multipart. Retorna URL pública do arquivo.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"filename":{"type":"string"}}}}}}}}},"/onboarding":{"get":{"summary":"Listar onboardings (admin)","tags":["Onboarding"],"description":"Lista todos os onboardings com filtro por status e paginação.","parameters":[{"schema":{"type":"string","enum":["draft","submitted","processing","review","approved","live"]},"in":"query","name":"status","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}}}}}}}}}},"post":{"summary":"Criar onboarding (admin)","tags":["Onboarding"],"description":"Cria novo onboarding e gera token + link para o formulário público. `template_chave` escolhe o processo de implantação que o projeto vai seguir (ver GET /implantacao/templates); sem ela, o projeto nasce com o processo padrão de loja completa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome_fantasia":{"type":"string"},"contato_email":{"type":"string","format":"email"},"contato_whatsapp":{"type":"string"},"assigned_to":{"type":"string"},"template_chave":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/{id}":{"get":{"summary":"Detalhe do onboarding (admin)","tags":["Onboarding"],"description":"Retorna dados de um onboarding pelo UUID. Com permissão `onboardings`, retorna tudo. Com apenas `implantacao`, os campos de PII e documento vêm omitidos.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/{id}/status":{"patch":{"summary":"Atualizar status do onboarding (admin)","tags":["Onboarding"],"description":"Atualiza o status de um onboarding. Valores válidos: draft, submitted, processing, review, approved, live.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["draft","submitted","processing","review","approved","live"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/{id}/contato":{"patch":{"summary":"Atualizar dados de contato do onboarding (admin)","tags":["Onboarding"],"description":"Corrige nome/e-mail/WhatsApp do contato. O e-mail é o destino do código de verificação do portal de conexões. Campo ausente não é alterado; string vazia limpa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"contato_nome":{"type":"string"},"contato_email":{"type":"string"},"contato_whatsapp":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/{id}/provision":{"post":{"summary":"Provisionar loja (idempotente)","tags":["Onboarding"],"description":"Executa (ou re-executa) o provisionamento da loja: cria tenant, owner, trial, categorias, produtos e site offline. Idempotente e best-effort.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/onboarding/{id}/publicar":{"patch":{"summary":"Publicar loja (offline -> online)","tags":["Onboarding"],"description":"Muda o site para status online e o onboarding para live. Requer provisionamento prévio.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/implantacao/templates":{"get":{"summary":"Listar templates de implantação (admin)","tags":["Implantacao"],"description":"Processos disponíveis na criação de um projeto: os versionados em código (origem=catalogo, semeados na primeira listagem) e os que o time criou pela tela (origem=custom). Por padrão só os ativos, que é o que a tela de criação consome; `incluir_inativos=true` traz também os desativados, para a tela de processos conseguir reativar (sem isso, desativar é porta de mão única). Ordenados por `ordem`. `fases` é a contagem de fases e `dias_previstos_total` a soma dos prazos delas, nulo quando nenhuma fase tem prazo (o caso dos templates internos, que não têm SLA). O `conteudo` NÃO vem aqui: para editar, leia `GET /implantacao/templates/:id`.","parameters":[{"schema":{"type":"string","enum":["cliente","interno"]},"in":"query","name":"escopo","required":false},{"schema":{"type":"string","enum":["true"]},"in":"query","name":"incluir_inativos","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"chave":{"type":"string"},"nome":{"type":"string"},"descricao":{"type":"string","nullable":true},"escopo":{"type":"string"},"ordem":{"type":"integer"},"ativo":{"type":"boolean"},"origem":{"type":"string"},"fases":{"type":"integer"},"dias_previstos_total":{"type":"integer","nullable":true}},"additionalProperties":true}}},"additionalProperties":true}}}}}},"post":{"summary":"Criar template de implantação (admin)","tags":["Implantacao"],"description":"Cria um processo próprio do time (nasce sempre origem=custom). Sem `chave` no body, ela é derivada do nome (minúsculo, sem acento, hífen) e ganha sufixo numérico se já existir. Com `chave` explícita, chave repetida é 409: quem escolheu a chave quer aquela. `conteudo` passa pela MESMA validação do instanciar, então conteúdo inválido é 400 e nunca vira linha quebrada no banco.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"descricao":{"type":"string","nullable":true},"escopo":{"type":"string","enum":["cliente","interno"]},"conteudo":{"type":"array","items":{"type":"object","additionalProperties":true}},"ordem":{"type":"integer"},"chave":{"type":"string"}},"required":["nome","escopo","conteudo"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/templates/{id}":{"get":{"summary":"Detalhe de um template de implantação (admin)","tags":["Implantacao"],"description":"O mesmo objeto da listagem MAIS o `conteudo` (as fases). É o que a tela precisa ler antes de editar: um PATCH de `conteudo` substitui o processo inteiro, e mandar isso sem ter carregado as fases atuais apagaria o trabalho de quem montou o template. Traz template desativado também, senão não haveria como olhar (nem reativar) o que saiu da listagem.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Atualizar template de implantação (admin)","tags":["Implantacao"],"description":"Atualiza nome, descrição, conteúdo, ordem e ativo. Template origem=catalogo aceita só `ativo` e `ordem`: mudar nome ou conteúdo de um template semeado devolve 409 template_do_catalogo, porque o seed é idempotente por chave e não desfaria a edição, deixando código e banco discordando em silêncio. Para mudar o processo de um template do catálogo, duplique.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"descricao":{"type":"string","nullable":true},"conteudo":{"type":"array","items":{"type":"object","additionalProperties":true}},"ativo":{"type":"boolean"},"ordem":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Desativar template de implantação (admin)","tags":["Implantacao"],"description":"Marca `ativo = false`. NÃO apaga: `implantacao_projetos.template_chave` de projeto antigo aponta para a chave, e apagar a linha faria o portfólio perder o nome do processo desses projetos. Template desativado some da listagem e da criação, e continua resolvendo nome no histórico.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/templates/{id}/duplicar":{"post":{"summary":"Duplicar template de implantação (admin)","tags":["Implantacao"],"description":"Cria uma cópia origem=custom do template, com chave nova. É o caminho para partir de um processo do catálogo (que não aceita edição) e ajustar o que for preciso. Sem `nome`, usa o nome do original com \"(cópia)\".","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/templates/de-projeto/{projetoId}":{"post":{"summary":"Criar template a partir de um projeto (admin)","tags":["Implantacao"],"description":"Lê as fases, tarefas, checklists e pedidos de documento REAIS do projeto e salva como template origem=custom. O estado de execução fica para trás: status, responsável, prazo, datas, item de checklist marcado e arquivo já enviado. Sem `escopo`, herda o tipo do projeto. Projeto sem fase nenhuma é 400.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"escopo":{"type":"string","enum":["cliente","interno"]}},"required":["nome"]}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"projetoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos":{"get":{"summary":"Listar projetos de implantação (admin)","tags":["Implantacao"],"description":"Lista paginada dos projetos do tipo pedido (`tipo`, default `cliente`), com filtro por status. Projeto arquivado fica fora a menos de `arquivados=true`. Os defaults espelham os do portfólio: quem pede \"os projetos\" está pedindo implantação de cliente em andamento, não demanda interna nem projeto que a casa parou.","parameters":[{"schema":{"type":"string","enum":["nao_iniciado","em_andamento","em_pausa","concluido","cancelado"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","enum":["cliente","interno"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","enum":["true"]},"in":"query","name":"arquivados","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","additionalProperties":true}},"meta":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"page_size":{"type":"integer"}},"additionalProperties":true}},"additionalProperties":true}}}}}},"post":{"summary":"Criar projeto interno de implantação (admin)","tags":["Implantacao"],"description":"Cria um projeto sem cliente (demanda da casa: produção de tema, campanha, mutirão de catálogo) no mesmo motor de fases e tarefas da implantação. Instancia o template escolhido (`template_chave`, padrão `interno-branco`) e, com `iniciar` (default true), já liga o relógio. `tipo=cliente` é recusado com 400 projeto_cliente_exige_onboarding.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"tipo":{"type":"string","enum":["cliente","interno"],"default":"interno"},"template_chave":{"type":"string"},"responsavel_id":{"type":"string","nullable":true},"previsao_go_live":{"type":"string","nullable":true},"iniciar":{"type":"boolean","default":true}},"required":["nome"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/{id}":{"get":{"summary":"Detalhe completo do projeto de implantação (admin)","tags":["Implantacao"],"description":"Retorna o projeto com etapas, tarefas, documentos, atualizações e progresso_pct.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Atualizar projeto de implantação (admin)","tags":["Implantacao"],"description":"Atualiza nome, status, previsão de go-live e/ou responsável pelo projeto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1},"status":{"type":"string","enum":["nao_iniciado","em_andamento","em_pausa","concluido","cancelado"]},"previsao_go_live":{"type":"string","nullable":true},"responsavel_id":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/by-onboarding/{onboardingId}":{"get":{"summary":"Projeto de implantação pelo onboarding_id (admin)","tags":["Implantacao"],"description":"Resolve o implantacao_projetos vinculado ao onboarding e retorna o mesmo ProjetoCompleto de GET /implantacao/projetos/:id. Permite ao web linkar por onboarding_id (sempre disponível na listagem) sem precisar mapear via GET /implantacao/projetos com paginação.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"onboardingId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/{id}/instanciar":{"post":{"summary":"Instanciar template no projeto (admin)","tags":["Implantacao"],"description":"Cria etapas/tarefas/documentos do template escolhido. Sem `template_chave` no body, usa a chave já gravada no projeto e, na falta dela, o padrão do tipo (cliente ou interno). Idempotente: no-op se o projeto já tiver etapas. A primeira fase só nasce em andamento se o projeto já foi iniciado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"template_chave":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/{id}/iniciar":{"post":{"summary":"Iniciar projeto de implantação (admin)","tags":["Implantacao"],"description":"Carimba `iniciado_em`, move o projeto para em_andamento e começa a primeira fase pendente. É este carimbo que liga o SLA: antes dele o projeto não tem previsão e não pode estar atrasado. Idempotente: projeto já iniciado volta como está, sem mover fase nem repetir o marco no feed.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/{id}/arquivar":{"post":{"summary":"Arquivar projeto de implantação (admin)","tags":["Implantacao"],"description":"Marca o projeto como arquivado (quem arquivou, quando e por quê). Arquivado sai da lista e dos KPIs do portfólio, e para de contar atraso e risco. Nada é apagado: o histórico continua inteiro e `desarquivar` desfaz.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"motivo":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/projetos/{id}/desarquivar":{"post":{"summary":"Desarquivar projeto de implantação (admin)","tags":["Implantacao"],"description":"Limpa arquivado_em/arquivado_por/motivo_arquivamento e devolve o projeto à lista e aos KPIs.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/etapas":{"post":{"summary":"Criar etapa de implantação (admin)","tags":["Implantacao"],"description":"Cria uma etapa fora do template padrão (ex.: fase custom por projeto).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["projeto_id","titulo"],"properties":{"projeto_id":{"type":"string","format":"uuid"},"titulo":{"type":"string"},"descricao":{"type":"string","nullable":true},"ordem":{"type":"integer"},"visivel_cliente":{"type":"boolean"},"dias_previstos":{"type":"integer","minimum":0,"nullable":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/etapas/{id}":{"patch":{"summary":"Atualizar etapa de implantação (admin)","tags":["Implantacao"],"description":"Atualiza campos da etapa. status=concluida primeiro roda o GATE de bloqueantes: varre o checklist de todas as tarefas da etapa e, se houver algum item bloqueante ainda feito=false, recusa com 422 `bloqueantes_pendentes` (body com `pendentes[]` — tarefa_id/tarefa_titulo/item_id/item_titulo). Sem bloqueante pendente, marca concluida_em e inicia a próxima etapa pendente (por ordem). Esse gate é só desta ação manual — o go-live automático (aplicarMarcoPublicar) NÃO passa por ele. status=em_andamento marca iniciada_em se ainda não setado. Qualquer outro status (reabertura) limpa concluida_em.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"titulo":{"type":"string"},"descricao":{"type":"string","nullable":true},"status":{"type":"string","enum":["pendente","em_andamento","concluida","bloqueada"]},"ordem":{"type":"integer"},"visivel_cliente":{"type":"boolean"},"dias_previstos":{"type":"integer","minimum":0,"nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover etapa de implantação (admin)","tags":["Implantacao"],"description":"Remove a etapa e, em cascata, suas tarefas e documentos vinculados.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"}}}},"/implantacao/tarefas":{"post":{"summary":"Criar tarefa de implantação (admin)","tags":["Implantacao"],"description":"Cria uma tarefa dentro de uma etapa (board do time).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["projeto_id","etapa_id","titulo"],"properties":{"projeto_id":{"type":"string","format":"uuid"},"etapa_id":{"type":"string","format":"uuid"},"titulo":{"type":"string"},"descricao":{"type":"string","nullable":true},"tipo":{"type":"string","enum":["interna","acao_cliente"]},"visivel_cliente":{"type":"boolean"},"responsavel_id":{"type":"string","format":"uuid","nullable":true},"prazo":{"type":"string","nullable":true},"status":{"type":"string","enum":["a_fazer","em_progresso","em_revisao","ajustes_solicitados","concluida","bloqueada"]},"ordem":{"type":"integer"},"checklist":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"id":{"type":"string"},"titulo":{"type":"string"},"feito":{"type":"boolean"},"bloqueante":{"type":"boolean"}}}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/tarefas/{id}":{"patch":{"summary":"Atualizar tarefa de implantação (admin)","tags":["Implantacao"],"description":"Atualiza campos da tarefa. status=concluida marca concluida_em; qualquer outro status (reabertura) limpa concluida_em.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"titulo":{"type":"string"},"descricao":{"type":"string","nullable":true},"status":{"type":"string","enum":["a_fazer","em_progresso","em_revisao","ajustes_solicitados","concluida","bloqueada"]},"responsavel_id":{"type":"string","format":"uuid","nullable":true},"prazo":{"type":"string","nullable":true},"tipo":{"type":"string","enum":["interna","acao_cliente"]},"visivel_cliente":{"type":"boolean"},"ordem":{"type":"integer"},"checklist":{"type":"array","maxItems":50,"items":{"type":"object","properties":{"id":{"type":"string"},"titulo":{"type":"string"},"feito":{"type":"boolean"},"bloqueante":{"type":"boolean"}}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover tarefa de implantação (admin)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"}}}},"/implantacao/documentos":{"post":{"summary":"Criar pendência de documento (admin)","tags":["Implantacao"],"description":"Cria uma pendência de documento (checklist) para o cliente enviar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["projeto_id","titulo"],"properties":{"projeto_id":{"type":"string","format":"uuid"},"etapa_id":{"type":"string","format":"uuid","nullable":true},"tarefa_id":{"type":"string","format":"uuid","nullable":true},"titulo":{"type":"string"},"descricao":{"type":"string","nullable":true},"obrigatorio":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/documentos/{id}/revisar":{"patch":{"summary":"Revisar documento enviado (admin)","tags":["Implantacao"],"description":"Aprova ou rejeita um documento enviado. rejeitado exige motivo_rejeicao.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["aprovado","rejeitado"]},"motivo_rejeicao":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/documentos/{id}/url":{"get":{"summary":"URL assinada do documento (admin)","tags":["Implantacao"],"description":"Retorna URL assinada (5min) do arquivo no bucket privado implantacao-docs.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"expires_in":{"type":"integer"}},"additionalProperties":true}}}}}}},"/implantacao/documentos/{id}":{"delete":{"summary":"Remover pendência/documento de implantação (admin)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Default Response"}}}},"/implantacao/atualizacoes":{"post":{"summary":"Postar atualização no projeto (admin)","tags":["Implantacao"],"description":"Cria um comentário, marco ou update de sistema no feed do projeto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["projeto_id","mensagem"],"properties":{"projeto_id":{"type":"string","format":"uuid"},"mensagem":{"type":"string"},"tipo":{"type":"string","enum":["comentario","marco","sistema"]},"visivel_cliente":{"type":"boolean"},"etapa_id":{"type":"string","format":"uuid","nullable":true},"tarefa_id":{"type":"string","format":"uuid","nullable":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/responsaveis":{"get":{"summary":"Listar responsáveis atribuíveis a etapas/tarefas de implantação (admin)","tags":["Implantacao"],"description":"Retorna o time da plataforma (profiles com role=super_admin, ativo=true) — os únicos perfis com acesso ao backoffice de implantação e, portanto, atribuíveis como responsável em qualquer projeto (a Central de Implantação é cross-tenant; não faz sentido restringir por account_id de um tenant específico).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"nome":{"type":"string","nullable":true},"email":{"type":"string","nullable":true},"avatar_url":{"type":"string","nullable":true}},"additionalProperties":true}}},"additionalProperties":true}}}}}}},"/implantacao/portfolio":{"get":{"summary":"Portfólio de projetos de implantação (admin)","tags":["Implantacao"],"description":"Visão macro do head de implantação: KPIs agregados, os projetos do tipo pedido enriquecidos (progresso, etapa atual, SLA, pendências, responsável, contrato, template) e carga de trabalho por responsável de projeto. `tipo` separa o portfólio de clientes (default) do de projetos internos, e vale para lista, KPIs e carga. Projeto arquivado fica fora da lista (a menos de `arquivados=true`) e SEMPRE fora dos KPIs e da carga. Atraso e risco só contam para projeto iniciado e não arquivado. Os demais filtros (status, responsavel_id, atrasados=true, q por nome) se aplicam só à lista.","parameters":[{"schema":{"type":"string","enum":["nao_iniciado","em_andamento","em_pausa","concluido","cancelado"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"responsavel_id","required":false},{"schema":{"type":"string","enum":["true"]},"in":"query","name":"atrasados","required":false},{"schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"string","enum":["cliente","interno"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","enum":["true"]},"in":"query","name":"arquivados","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"kpis":{"type":"object","additionalProperties":true},"projetos":{"type":"array","items":{"type":"object","additionalProperties":true}},"carga":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}}}}},"/implantacao/projetos/{id}/contrato":{"post":{"summary":"Gerar documento assinável de implantação (admin)","tags":["Implantacao"],"description":"Renderiza o template do tipo pedido (`?tipo=contrato` — padrão — ou `?tipo=termo_entrega`) com as variáveis informadas + contrato_numero (gerado automaticamente, prefixo VH/TE) e versao_documento, calcula o hash SHA-256 do HTML final e cria o documento (status=enviado). 409 contrato_ja_existe se já houver um documento ATIVO DESSE TIPO (não cancelado) para o projeto — é preciso cancelar o atual antes de gerar outro; contrato e termo de entrega coexistem sem conflito. `logo_url` é opcional: quando não vem (ou vem vazia), a rota injeta a logo oficial `{APP_URL}/varejo-hub.svg` no timbre.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["variaveis"],"properties":{"variaveis":{"type":"object","additionalProperties":{"type":"string"}}}}}},"required":true},"parameters":[{"schema":{"type":"string","enum":["contrato","contrato_marketing","termo_entrega"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"get":{"summary":"Ver documento assinável ativo do projeto (admin)","tags":["Implantacao"],"description":"Retorna o documento ativo (status <> cancelado) do tipo pedido (`?tipo=contrato` — padrão — ou `?tipo=termo_entrega`), com a trilha de eventos (`eventos[]`) e `documento_html` (documento pronto pra exibir/imprimir — `conteudo_html` + selo de assinatura quando já assinado). 404 se não houver.","parameters":[{"schema":{"type":"string","enum":["contrato","contrato_marketing","termo_entrega"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/contratos/{id}/cancelar":{"post":{"summary":"Cancelar contrato de implantação (admin)","tags":["Implantacao"],"description":"Cancela um contrato com status=enviado. Contrato já assinado NÃO pode ser cancelado (409).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/meu":{"get":{"summary":"Minha implantação (cliente logado)","tags":["Implantacao"],"description":"Retorna a visão de acompanhamento do projeto de implantação do tenant do usuário logado. null se não houver.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"additionalProperties":true}}}}}}},"/implantacao/public/{token}":{"get":{"summary":"Buscar visão de acompanhamento pelo token (público)","tags":["Implantacao"],"description":"Retorna a visão do cliente (timeline, pendências, feed) do projeto vinculado ao token do onboarding.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","nullable":true,"additionalProperties":true}}}}}}},"/implantacao/public/{token}/documentos/{docId}/upload":{"post":{"summary":"Upload de documento (público)","tags":["Implantacao"],"description":"Faz upload de arquivo para uma pendência de documento no bucket privado implantacao-docs. Requer @fastify/multipart.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"docId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"}},"additionalProperties":true}}}}}}},"/implantacao/public/{token}/documentos/{docId}/url":{"get":{"summary":"URL assinada do documento (público)","tags":["Implantacao"],"description":"Retorna URL assinada (5min) do arquivo enviado, validando token → projeto → documento.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"docId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"expires_in":{"type":"integer"}},"additionalProperties":true}}}}}}},"/implantacao/public/{token}/tarefas/{tarefaId}/arquivo":{"post":{"summary":"Anexar arquivo numa tarefa do cliente (público)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tarefaId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/tarefas/{tarefaId}/arquivo/{docId}":{"delete":{"summary":"Remover anexo que o cliente enviou (público)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tarefaId","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"docId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/tarefas/{tarefaId}/responder":{"post":{"summary":"Responder tarefa do cliente (público)","tags":["Implantacao"],"description":"Conclui, entrega, confirma ou pede ajustes numa tarefa de ação do cliente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["acao"],"properties":{"acao":{"type":"string","enum":["concluir","ajustes"]},"comentario":{"type":"string","maxLength":2000}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tarefaId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/tarefas/{tarefaId}/aprovar":{"post":{"summary":"Aprovar tarefa de ação do cliente (público)","tags":["Implantacao"],"description":"Conclui uma tarefa tipo acao_cliente (ex.: \"Aprovar a loja\") e posta um marco visível no feed.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"tarefaId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"additionalProperties":true}}}}}}},"/implantacao/public/{token}/contrato":{"get":{"summary":"Ver documento assinável do projeto pelo token (público)","tags":["Implantacao"],"description":"Retorna o documento do tipo pedido (`?tipo=contrato` — padrão — ou `?tipo=termo_entrega`) com status enviado ou assinado (cancelado ou inexistente → 404), incluindo `documento_html` (documento pronto pra exibir/imprimir — `conteudo_html` + selo de assinatura quando já assinado). Registra evento \"visualizado\" (best-effort).","parameters":[{"schema":{"type":"string","enum":["contrato","contrato_marketing","termo_entrega"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"tipo":{"type":"string"},"titulo":{"type":"string"},"conteudo_html":{"type":"string"},"documento_html":{"type":"string"},"status":{"type":"string"},"hash_sha256":{"type":"string"},"versao_template":{"type":"string"},"assinado_em":{"type":"string","nullable":true},"assinante_nome":{"type":"string","nullable":true}},"additionalProperties":true}}}}}}},"/implantacao/public/{token}/contrato/assinar":{"post":{"summary":"Assinar documento eletronicamente (público)","tags":["Implantacao"],"description":"Click-to-sign do tipo pedido (`?tipo=contrato` — padrão — ou `?tipo=termo_entrega`): valida aceite/nome/documento no boundary, marca o documento como assinado com IP/user-agent do assinante, registra o evento na trilha jurídica e, best-effort, cria um marco visível no feed, aprova o documento de upload equivalente pendente (ponte com o fluxo antigo, só o contrato tem) e envia um e-mail de confirmação (Resend) para o contato do onboarding, se houver.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{},"documento":{},"aceite":{}}}}}},"parameters":[{"schema":{"type":"string","enum":["contrato","contrato_marketing","termo_entrega"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"assinado_em":{"type":"string"}},"additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/otp/enviar":{"post":{"summary":"Enviar código de verificação das conexões (público)","tags":["Implantacao"],"description":"Envia OTP ao e-mail do briefing (client_onboardings.contato_email) para liberar a etapa de conexões. Cooldown de 60s e teto de 8/dia por contato.","parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/otp/verificar":{"post":{"summary":"Verificar código e abrir sessão step-up (público)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["codigo"],"properties":{"codigo":{"type":"string","minLength":6,"maxLength":6}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/pagamento":{"post":{"summary":"Conectar conta de pagamentos por credencial (público, step-up)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["secret_key"],"properties":{"provider":{"type":"string","enum":["pagarme","dom_pagamentos"]},"secret_key":{"type":"string","minLength":8},"public_key":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/pagamento/mercado-pago/iniciar":{"post":{"summary":"Iniciar OAuth Mercado Pago pelo portal (público, step-up)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/oauth/mercado-pago/callback":{"post":{"summary":"Callback OAuth Mercado Pago do portal (público)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string"},"state":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/entrega/iniciar":{"post":{"summary":"Iniciar OAuth Melhor Envio pelo portal (público, step-up)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/oauth/melhor-envio/callback":{"post":{"summary":"Callback OAuth Melhor Envio do portal (público)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["code","state"],"properties":{"code":{"type":"string"},"state":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/entrega/frenet":{"post":{"summary":"Conectar Frenet por token de API (público, step-up)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["api_token"],"properties":{"api_token":{"type":"string","minLength":8},"cep_origem":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/erp/iniciar":{"post":{"summary":"Iniciar OAuth do sistema de gestão pelo portal (público, step-up)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["provider"],"properties":{"provider":{"type":"string","enum":["bling","tiny"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/erp/tiny/credenciais":{"post":{"summary":"Salvar credencial do aplicativo Tiny pelo portal (público, step-up)","tags":["Implantacao"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["client_id","client_secret"],"properties":{"client_id":{"type":"string","minLength":3},"client_secret":{"type":"string","minLength":8}}}}},"required":true},"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/implantacao/public/{token}/conexoes/erp/tiny/webhook-url":{"get":{"summary":"Recuperar a URL de notificação do Tiny pelo portal (público, step-up)","tags":["Implantacao"],"parameters":[{"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"},"in":"path","name":"token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados":{"get":{"summary":"Chamados da loja (lojista)","tags":["Suporte"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"chamados":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}}}},"post":{"summary":"Abrir chamado (lojista)","tags":["Suporte"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tipo":{"type":"string"},"assunto":{"type":"string"},"mensagem":{"type":"string"},"erro":{"type":"object","additionalProperties":true}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados/{id}":{"get":{"summary":"Detalhe do chamado (lojista)","tags":["Suporte"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados/{id}/mensagens":{"post":{"summary":"Responder chamado (lojista)","tags":["Suporte"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mensagem":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados/{id}/mensagens/{mensagemId}/anexos":{"post":{"summary":"Anexar arquivo numa mensagem (lojista)","tags":["Suporte"],"description":"Multipart, campo `file`. Imagem, PDF ou zip, até 10 MB e até 5 por mensagem.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"mensagemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados/{id}/resolver":{"post":{"summary":"Marcar chamado como resolvido (lojista)","tags":["Suporte"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/chamados/{id}/avaliacao":{"post":{"summary":"Avaliar o atendimento do chamado resolvido (lojista)","tags":["Suporte"],"description":"Nota inteira de 0 a 10 e comentário opcional de até 1000 caracteres. Uma avaliação por chamado.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nota":{},"comentario":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/fila":{"get":{"summary":"Fila de chamados (equipe)","tags":["Suporte"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string"},"in":"query","name":"responsavel","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"chamados":{"type":"array","items":{"type":"object","additionalProperties":true}}},"additionalProperties":true}}}}}}},"/suporte/fila/nps":{"get":{"summary":"NPS do suporte no período (equipe)","tags":["Suporte"],"description":"Promotor: 9 e 10. Neutro: 7 e 8. Detrator: 0 a 6. `nps` é nulo sem avaliações. `dias` de 1 a 365 (padrão 90).","parameters":[{"schema":{"type":"string"},"in":"query","name":"dias","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/fila/{id}":{"get":{"summary":"Atendimento do chamado (equipe)","tags":["Suporte"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Mudar situação ou responsável do chamado (equipe)","tags":["Suporte"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"responsavel_id":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/fila/{id}/mensagens":{"post":{"summary":"Responder chamado ou deixar nota interna (equipe)","tags":["Suporte"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mensagem":{"type":"string"},"interna":{"type":"boolean"},"status":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/suporte/fila/{id}/mensagens/{mensagemId}/anexos":{"post":{"summary":"Anexar arquivo numa mensagem (equipe)","tags":["Suporte"],"description":"Multipart, campo `file`. Mesmas regras do lojista; o arquivo fica sob a loja do chamado.","parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"mensagemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/equipe":{"get":{"summary":"Equipe para menções (pessoas e agentes)","tags":["Marketing (backoffice)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts":{"get":{"summary":"Posts para quadro, calendário e linha do tempo","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false},{"schema":{"type":"string"},"in":"query","name":"incluir_arquivados","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Criar post","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}":{"get":{"summary":"Detalhe do post","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Editar post","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir post em Ideia ou Em produção (só humano)","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/mover":{"post":{"summary":"Mudar a etapa do post","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"tarefa_id":{"type":"string"},"briefing":{"type":"string","maxLength":2000}},"required":["status"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/aprovar":{"post":{"summary":"Aprovar e agendar (só humano)","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"publicar_em":{"type":"string"}},"required":["publicar_em"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/pedir-ajuste":{"post":{"summary":"Pedir ajuste à Luna (só humano)","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sugestoes":{"type":"array","items":{"type":"string"}},"texto":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/publicado":{"post":{"summary":"Marcar como publicado (com o link)","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"link":{"type":"string"}},"required":["link"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/versoes":{"post":{"summary":"Nova versão das artes","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nota":{"type":"string"},"custo_usd":{"type":"number"},"tarefa_id":{"type":"string"},"opcao_grupo":{"type":"string"},"opcao_rotulo":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/versoes/{numero}/midias":{"post":{"summary":"Anexar uma arte à versão (multipart, campo file)","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"ordem","required":false},{"schema":{"type":"string"},"in":"query","name":"largura","required":false},{"schema":{"type":"string"},"in":"query","name":"altura","required":false},{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"numero","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/versoes/{numero}/concluir":{"post":{"summary":"Concluir a versão (vira a atual)","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tarefa_id":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"numero","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/kit":{"get":{"summary":"Kit de publicação","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/posts/{id}/comentarios":{"post":{"summary":"Comentar com menções","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"texto":{"type":"string"},"tarefa_id":{"type":"string"}},"required":["texto"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/comentarios/{id}":{"delete":{"summary":"Apagar o próprio comentário","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/campanhas":{"get":{"summary":"Campanhas","tags":["Marketing (backoffice)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Criar campanha","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/campanhas/{id}":{"patch":{"summary":"Editar campanha","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/pautas":{"post":{"summary":"Pedir pautas à Luna","tags":["Marketing (backoffice)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dias":{"type":"array","items":{"type":"string"}}},"required":["dias"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/resumo":{"get":{"summary":"Números do topo da aba","tags":["Marketing (backoffice)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/pulso":{"get":{"summary":"Espera longa: eventos novos do Marketing","tags":["Marketing (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/aguardar":{"get":{"summary":"Espera longa: próxima tarefa do agente (sem reservar)","tags":["Marketing (agente)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/reservar":{"post":{"summary":"Reservar a tarefa","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/abrir":{"post":{"summary":"Abrir ou assumir a tarefa do post (arte feita fora da fila)","tags":["Marketing (agente)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"post_id":{"type":"string"},"motivo":{"type":"string"}},"required":["post_id","motivo"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas":{"get":{"summary":"Tarefas do agente","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"estado","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}":{"get":{"summary":"Detalhe da tarefa","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/iniciar":{"post":{"summary":"Começar a tarefa","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/sinal":{"post":{"summary":"Sinal de vida da tarefa","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/aguardar":{"post":{"summary":"Esperar resposta ou liberação","tags":["Marketing (agente)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"pergunta":{"type":"string"},"custo_estimado_usd":{"type":"number"}},"required":["pergunta"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/concluir":{"post":{"summary":"Concluir a tarefa","tags":["Marketing (agente)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"resumo":{"type":"string"}},"required":["resumo"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/falhar":{"post":{"summary":"Registrar falha da tarefa","tags":["Marketing (agente)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"erro":{"type":"string"}},"required":["erro"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/tarefas/{id}/liberar":{"post":{"summary":"Liberar gasto para a tarefa (super_admin)","tags":["Marketing (agente)"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"valor_usd":{"type":"number"}},"required":["valor_usd"]}}},"required":true},"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/saldo":{"get":{"summary":"Saldo e teto do agente","tags":["Marketing (agente)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"tarefa","required":false},{"schema":{"type":"string"},"in":"query","name":"estimativa","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/marketing/agente/ativar":{"post":{"summary":"Ativar a Luna e gerar a senha dela (super_admin)","tags":["Marketing (agente)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/notificacoes":{"get":{"summary":"Notificações da pessoa","tags":["Notificações (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"filtro","required":false},{"schema":{"type":"string"},"in":"query","name":"antes","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/notificacoes/pulso":{"get":{"summary":"Espera longa: notificações novas","tags":["Notificações (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"cursor","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/notificacoes/{id}/lida":{"post":{"summary":"Marcar como lida","tags":["Notificações (backoffice)"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/admin/notificacoes/lidas":{"post":{"summary":"Marcar todas como lidas","tags":["Notificações (backoffice)"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/b2b/empresas":{"get":{"summary":"Listar empresas B2B","tags":["B2B - Vendas Atacado"],"description":"Lista empresas B2B do tenant com filtro por status operacional, por status de aprovação e busca por razão social, nome fantasia ou CNPJ.","parameters":[{"schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"string","enum":["ativa","em_espera","inativa"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","enum":["pendente","aprovada","recusada"]},"in":"query","name":"aprovacao_status","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Cadastra empresa B2B com validação de CNPJ e criação automática de unidade matriz. Detecta duplicidade por CNPJ no tenant.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["razao_social","cnpj_matriz"],"properties":{"razao_social":{"type":"string"},"nome_fantasia":{"type":"string"},"cnpj_matriz":{"type":"string"},"notas":{"type":"string"},"endereco_matriz":{"type":"object"},"ie":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/b2b/empresas/{id}":{"get":{"summary":"Detalhe da empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Retorna empresa com todas as unidades vinculadas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Atualização parcial (razao_social, nome_fantasia, notas, status).","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Soft delete - marca empresa como inativa.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/empresas/{id}/contatos":{"get":{"summary":"Listar contatos da empresa","tags":["B2B - Vendas Atacado"],"description":"Agrega contatos de todas as unidades da empresa com dados do cliente vinculado (email, nome, telefone).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/empresas/{id}/pedidos":{"get":{"summary":"Pedidos da empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Retorna pedidos B2B paginados de todas as unidades da empresa. Aceita filtro por status.","parameters":[{"schema":{"type":"integer","default":50,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","default":0},"in":"query","name":"offset","required":false},{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/empresas/{id}/aprovar":{"patch":{"summary":"Aprovar empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Aprova solicitação de self-signup. Marca empresa como ativa, aplica lista/catálogo/prazos nas unidades (opcional) e dispara email de aprovação para o comprador.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nota":{"type":"string"},"aprovacao_nota":{"type":"string"},"lista_preco_id":{"type":"string"},"catalogo_id":{"type":"string"},"payment_terms_ativos":{"type":"array","items":{"type":"string"}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/empresas/{id}/recusar":{"patch":{"summary":"Recusar empresa B2B","tags":["B2B - Vendas Atacado"],"description":"Recusa solicitação de self-signup com nota opcional. Marca a empresa como inativa e dispara email de recusa.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nota":{"type":"string"},"aprovacao_nota":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/empresas/{empresaId}/unidades":{"post":{"summary":"Criar unidade B2B","tags":["B2B - Vendas Atacado"],"description":"Cria unidade vinculada à empresa. Valida CNPJ, IE, endereço e payment_terms. Defesa cross-tenant em lista_preco_id e catalogo_id.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","cnpj"],"properties":{"nome":{"type":"string"},"cnpj":{"type":"string"},"ie":{"type":"string"},"endereco":{"type":"object"},"endereco_jsonb":{"type":"object"},"payment_terms_ativos":{"type":"array","items":{"type":"string"}},"lista_preco_id":{"type":"string"},"catalogo_id":{"type":"string"},"pedido_minimo_centavos":{"type":"integer"},"pedido_minimo_itens":{"type":"integer"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"empresaId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/unidades/{id}":{"get":{"summary":"Detalhe da unidade B2B","tags":["B2B - Vendas Atacado"],"description":"Retorna dados completos de uma unidade B2B.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar unidade B2B","tags":["B2B - Vendas Atacado"],"description":"Atualização parcial de unidade com whitelist completa (nome, cnpj, ie, endereço, payment_terms, lista, catálogo, pedido mínimo).","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir unidade B2B","tags":["B2B - Vendas Atacado"],"description":"Remove unidade permanentemente (hard delete).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/unidades/{id}/contatos":{"post":{"summary":"Vincular contato à unidade","tags":["B2B - Vendas Atacado"],"description":"Vincula ou cria cliente como contato da unidade. Aceita cliente_id existente ou email/telefone para upsert. Registra consent LGPD automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cliente_id":{"type":"string"},"email":{"type":"string"},"nome":{"type":"string"},"telefone":{"type":"string"},"role":{"type":"string","enum":["comprador","admin"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/unidades/{id}/contatos/{clienteId}":{"delete":{"summary":"Remover contato da unidade","tags":["B2B - Vendas Atacado"],"description":"Remove vínculo do contato com a unidade B2B.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"clienteId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/listas-preco":{"get":{"summary":"Listar listas de preço","tags":["B2B - Vendas Atacado"],"description":"Lista de preço B2B do tenant. Default: só ativas. ?ativa=false para inativas, ?ativa= (vazio) para todas.","parameters":[{"schema":{"type":"string","enum":["true","false",""]},"in":"query","name":"ativa","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar lista de preço","tags":["B2B - Vendas Atacado"],"description":"Cria nova lista de preço B2B.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"descricao":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/b2b/listas-preco/{id}":{"get":{"summary":"Detalhe da lista de preço","tags":["B2B - Vendas Atacado"],"description":"Retorna dados de uma lista de preço.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar lista de preço","tags":["B2B - Vendas Atacado"],"description":"Atualiza nome, descrição ou status ativo da lista.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar lista de preço","tags":["B2B - Vendas Atacado"],"description":"Soft delete - marca lista como inativa.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/listas-preco/{id}/itens":{"get":{"summary":"Listar itens da lista","tags":["B2B - Vendas Atacado"],"description":"Retorna itens de preço com faixas de volume. Aceita ?include=produto para JOIN. Filtro por produto_id ou busca textual por nome.","parameters":[{"schema":{"type":"string"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string"},"in":"query","name":"q","required":false},{"schema":{"type":"string","enum":["produto"]},"in":"query","name":"include","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar item de lista","tags":["B2B - Vendas Atacado"],"description":"Adiciona item com preço e faixa de quantidade à lista de preço.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","preco_centavos"],"properties":{"produto_id":{"type":"string"},"variacao_id":{"type":"string"},"preco_centavos":{"type":"integer"},"faixa_qtd_min":{"type":"integer","default":1},"faixa_qtd_max":{"type":["integer","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/lista-itens/{itemId}":{"patch":{"summary":"Atualizar item de lista","tags":["B2B - Vendas Atacado"],"description":"Atualiza preço e/ou faixas de quantidade de um item.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"preco_centavos":{"type":"integer"},"faixa_qtd_min":{"type":"integer"},"faixa_qtd_max":{"type":["integer","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir item de lista","tags":["B2B - Vendas Atacado"],"description":"Remove item de preço permanentemente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"itemId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/listas-preco/{id}/duplicar":{"post":{"summary":"Duplicar lista de preço","tags":["B2B - Vendas Atacado"],"description":"Cria cópia da lista de preço com todos os itens. Nome opcional (default: original + cópia).","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/b2b/catalogos":{"get":{"summary":"Listar catálogos B2B","tags":["B2B - Vendas Atacado"],"description":"Retorna catálogos do tenant ordenados por data de criação.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar catálogo B2B","tags":["B2B - Vendas Atacado"],"description":"Cria catálogo com lista de IDs de produtos inclusos.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string"},"produtos_ids":{"type":"array","items":{"type":"string"}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/b2b/catalogos/{id}":{"patch":{"summary":"Atualizar catálogo B2B","tags":["B2B - Vendas Atacado"],"description":"Atualiza nome e/ou lista de produtos do catálogo.","requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir catálogo B2B","tags":["B2B - Vendas Atacado"],"description":"Remove catálogo permanentemente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b/kpis":{"get":{"summary":"KPIs do B2B","tags":["B2B - Vendas Atacado"],"description":"Dashboard B2B: empresas ativas, pedidos do mês, ticket médio B2B vs B2C, boletos vencidos e top 5 empresas. Cache Redis 60s.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/b2b-public/me":{"get":{"summary":"Dados do comprador B2B","tags":["B2B - Storefront Público"],"description":"Retorna unidades onde o email é contato. Resposta uniforme (anti-enumeração).","parameters":[{"schema":{"type":"string"},"in":"query","name":"email","required":false},{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/b2b-public/produto-preco":{"get":{"summary":"Consultar preço B2B","tags":["B2B - Storefront Público"],"description":"Resolve preço usando volume pricing da lista de preço da unidade. Se sem lista, retorna preco_base.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":false},{"schema":{"type":"string"},"in":"query","name":"unidade_id","required":false},{"schema":{"type":"string"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string"},"in":"query","name":"variacao_id","required":false},{"schema":{"type":"integer"},"in":"query","name":"qtd","required":false},{"schema":{"type":"integer"},"in":"query","name":"preco_base","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"preco_centavos":{"type":"integer"},"origem":{"type":"string","enum":["b2b","base"]}}}}}}}}},"/b2b-public/produto-faixas":{"get":{"summary":"Faixas de preço B2B","tags":["B2B - Storefront Público"],"description":"Lista faixas de volume pricing do produto na lista da unidade (badge ProductCard).","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":false},{"schema":{"type":"string"},"in":"query","name":"unidade_id","required":false},{"schema":{"type":"string"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string"},"in":"query","name":"variacao_id","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/b2b-public/unidade/{id}":{"get":{"summary":"Dados da unidade B2B","tags":["B2B - Storefront Público"],"description":"Retorna unidade para header do storefront.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/b2b-public/cnpj/{cnpj}":{"get":{"summary":"Consultar CNPJ","tags":["B2B - Storefront Público"],"description":"Lookup de CNPJ via BrasilAPI para autopreenchimento no self-signup.","parameters":[{"schema":{"type":"string"},"in":"path","name":"cnpj","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/b2b-public/solicitar-cadastro":{"post":{"summary":"Solicitar cadastro B2B","tags":["B2B - Storefront Público"],"description":"Self-signup de revendedor. Cria empresa pendente, unidade automática e vincula comprador. Dispara email pro lojista.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","cnpj","razao_social","comprador"],"properties":{"tenant_slug":{"type":"string"},"cnpj":{"type":"string"},"razao_social":{"type":"string"},"nome_fantasia":{"type":"string"},"inscricao_estadual":{"type":"string"},"contribuinte_icms":{"type":"boolean"},"endereco":{"type":"object"},"comprador":{"type":"object","required":["nome","email"],"properties":{"nome":{"type":"string"},"email":{"type":"string"},"telefone":{"type":"string"}}}}}}},"required":true},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"status":{"type":"string"},"reaberta":{"type":"boolean"}}}}}}}}},"/b2b-public/quick-order/resolver":{"post":{"summary":"Prévia de compra por SKU (quick order)","tags":["B2B - Storefront Público"],"description":"Resolve uma lista de SKU+quantidade contra o catálogo da unidade B2B: item, preço negociado já aplicado à quantidade, catálogo e estoque. NÃO adiciona nada ao carrinho. Exige Bearer da sessão OTP do comprador com vínculo na unidade.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","unidade_id","linhas"],"properties":{"tenant_slug":{"type":"string"},"unidade_id":{"type":"string"},"linhas":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"qtd":{}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"linhas":{"type":"array","items":{"type":"object","additionalProperties":true}},"resumo":{"type":"object","additionalProperties":true}}}}}}}}},"/b2b-public/quick-order/adicionar":{"post":{"summary":"Adicionar lista de SKUs ao carrinho (quick order)","tags":["B2B - Storefront Público"],"description":"Revalida as linhas e adiciona TODAS as válidas ao carrinho numa operação, devolvendo o que entrou, o que não entrou e o carrinho recalculado. Sucesso parcial é resposta 200 — o comprador vê linha a linha.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","unidade_id","session_token","linhas"],"properties":{"tenant_slug":{"type":"string"},"unidade_id":{"type":"string"},"session_token":{"type":"string"},"linhas":{"type":"array","items":{"type":"object","properties":{"sku":{"type":"string"},"qtd":{}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"linhas":{"type":"array","items":{"type":"object","additionalProperties":true}},"resumo":{"type":"object","additionalProperties":true},"carrinho":{"type":"object","additionalProperties":true}}}}}}}}},"/promocoes":{"get":{"summary":"Listar promoções","tags":["Promoções - Motor"],"description":"Listagem paginada de promoções com filtros por status, tipo_efeito e ativação.","parameters":[{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"ativo","required":false},{"schema":{"type":"string"},"in":"query","name":"tipo_efeito","required":false},{"schema":{"type":"string","enum":["automatica","cupom"]},"in":"query","name":"ativacao","required":false},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":100},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar promoção","tags":["Promoções - Motor"],"description":"Cria promoção com tipo de efeito, ativação (automática/cupom), acumulação, escopo e junction tables. Motor VTEX-grade.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","tipo_efeito"],"properties":{"nome":{"type":"string"},"descricao":{"type":"string"},"descricao_loja":{"type":"string"},"tipo_efeito":{"type":"string"},"ativacao":{"type":"string","enum":["automatica","cupom","ambas"],"default":"automatica"},"cupom_codigo":{"type":["string","null"]},"prioridade":{"type":"integer","default":0},"acumula_com_cupom":{"type":"boolean","default":true},"acumula_com_automatica":{"type":"boolean","default":true},"ativo":{"type":"boolean","default":true},"escopo":{"type":"string","default":"pedido"},"valor":{"type":"number"},"valor_maximo":{"type":["number","null"]},"compre_qtd":{"type":"integer"},"ganhe_qtd":{"type":"integer"},"valor_minimo":{"type":"number","default":0},"qtd_minima":{"type":"integer","default":0},"primeira_compra":{"type":"boolean","default":false},"combinavel":{"type":"boolean","default":false},"max_usos":{"type":["integer","null"]},"uso_por_cliente":{"type":"integer","default":1},"validade_inicio":{"type":["string","null"]},"validade_fim":{"type":["string","null"]},"produtos_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"categorias_ids":{"type":"array","items":{"type":"string","format":"uuid"}},"brindes":{"type":"array","items":{"type":"object","additionalProperties":true}},"faixas":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/promocoes/{id}":{"get":{"summary":"Detalhe da promoção","tags":["Promoções - Motor"],"description":"Retorna promoção com junction tables: produtos, categorias, brindes e faixas.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar promoção","tags":["Promoções - Motor"],"description":"Atualiza campos parciais e substitui junction tables se fornecidas.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desativar promoção","tags":["Promoções - Motor"],"description":"Soft delete (ativo = false).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/promocoes-public/produto-faixas":{"get":{"summary":"Faixas de promoção volume do produto","tags":["Promoções - Público"],"description":"Lista faixas de promoção de volume (B2C) ativas para o produto, ordenadas por qtd_min. Indica se não acumula com cupom. Usado pela PDP.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"faixas":{"type":"array","items":{"type":"object","properties":{"qtd_min":{"type":"integer"},"tipo_desconto":{"type":"string"},"valor_centavos":{"type":["null","integer"]},"percentual":{"type":["null","number"]}}}},"nao_acumula_cupom":{"type":"boolean"}}}}}}}}},"/branding":{"get":{"summary":"Dados de branding","tags":["Configurações - Brand Kit"],"description":"Retorna logo, favicon, OG image, cor primária, nome e slogan. Requer owner/manager.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar branding","tags":["Configurações - Brand Kit"],"description":"Atualiza campos de branding via whitelist. Valida cor hex e tamanho de slogan/nome.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"branding_logo_url":{"type":"string"},"branding_cor_primaria":{"type":"string"},"branding_nome_exibicao":{"type":"string"},"branding_slogan":{"type":"string"},"branding_favicon_url":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/branding/upload-url":{"post":{"summary":"Gerar URL de upload","tags":["Configurações - Brand Kit"],"description":"Gera signed upload URL para logo, favicon ou OG image no Storage.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["campo","mimetype"],"properties":{"campo":{"type":"string","enum":["logo","logo_dark","logo_quadrado","favicon","og"]},"mimetype":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/branding/{campo}":{"delete":{"summary":"Remover asset de branding","tags":["Configurações - Brand Kit"],"description":"Limpa coluna e remove arquivo do Storage (best-effort).","parameters":[{"schema":{"type":"string","enum":["logo","logo_dark","logo_quadrado","favicon","og"]},"in":"path","name":"campo","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/auth-otp/enviar":{"post":{"summary":"Enviar código OTP","tags":["Auth - OTP"],"description":"Gera e envia código OTP por email com branding do tenant. Público (sem JWT).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"tenant_slug":{"type":"string"},"contexto":{"type":"string","enum":["b2c","b2b","painel"]}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/auth-otp/checar":{"post":{"summary":"Checar se o e-mail tem conta na loja","tags":["Auth - OTP"],"description":"Usado pelo checkout para oferecer login por código quando o e-mail já é cliente. Público (sem JWT), rate-limited.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","tenant_slug"],"properties":{"email":{"type":"string"},"tenant_slug":{"type":"string"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"tem_conta":{"type":"boolean"}}}}}}}}},"/auth-otp/verificar":{"post":{"summary":"Verificar código OTP","tags":["Auth - OTP"],"description":"Valida código e retorna token_hash para criar sessão via verifyOtp. Cria user se não existir.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["email","codigo"],"properties":{"email":{"type":"string"},"codigo":{"type":"string"},"tenant_slug":{"type":"string"},"contexto":{"type":"string","enum":["b2c","b2b","painel"]}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/gateways/clearsale/config":{"post":{"summary":"Salvar credenciais ClearSale","tags":["Pagamentos - Antifraude (ClearSale)"],"description":"Upsert das credenciais ClearSale (api_key, client_id, client_secret). Atualiza toggles de antifraude por forma de pagamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["api_key","client_id","client_secret"],"properties":{"api_key":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"auto_approve_threshold":{"type":"number","description":"Score mínimo para auto-aprovação (default 90)"},"auto_reject_threshold":{"type":"number","description":"Score máximo para auto-rejeição (default 30)"},"sandbox":{"type":"boolean"},"antifraude_cartao":{"type":"boolean"},"antifraude_boleto":{"type":"boolean"},"antifraude_pix":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"ativo":{"type":"boolean"},"config":{"type":"object","additionalProperties":true}}}}}},"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"provider":{"type":"string"},"ativo":{"type":"boolean"},"config":{"type":"object","additionalProperties":true}}}}}}}},"delete":{"summary":"Remover credenciais ClearSale","tags":["Pagamentos - Antifraude (ClearSale)"],"description":"Remove credenciais, desativa antifraude em todas as formas de pagamento.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/gateways/clearsale/status":{"get":{"summary":"Verificar status da conexão ClearSale","tags":["Pagamentos - Antifraude (ClearSale)"],"description":"Verifica se ClearSale está conectada, testa autenticação e retorna toggles de antifraude.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"connected":{"type":"boolean"},"ativo":{"type":"boolean"},"sandbox":{"type":"boolean"},"error":{"type":"string","nullable":true},"auto_approve_threshold":{"type":"number"},"auto_reject_threshold":{"type":"number"},"antifraude_cartao":{"type":"boolean"},"antifraude_boleto":{"type":"boolean"},"antifraude_pix":{"type":"boolean"}}}}}}}}},"/gateways/clearsale/settings":{"patch":{"summary":"Atualizar configurações ClearSale","tags":["Pagamentos - Antifraude (ClearSale)"],"description":"Atualiza thresholds de aprovação/rejeição e toggles de antifraude por forma de pagamento.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"auto_approve_threshold":{"type":"number"},"auto_reject_threshold":{"type":"number"},"antifraude_cartao":{"type":"boolean"},"antifraude_boleto":{"type":"boolean"},"antifraude_pix":{"type":"boolean"},"ativo":{"type":"boolean"}}}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/webhook/clearsale/{accountId}":{"post":{"summary":"Receber webhook da ClearSale","tags":["Webhooks - ClearSale"],"description":"Rota pública. Valida clearsale-apikey via timingSafeEqual. Atualiza antifraude_status e score do pedido. Pode cancelar pedido se recusado/fraude.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["OrderId","Status"],"properties":{"OrderId":{"type":"string","description":"Número do pedido"},"Status":{"type":"string","description":"Status ClearSale (APA, APM, RPM, RPA, RPP, FRD, SUS, etc.)"},"Score":{"type":"number","nullable":true}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"antifraudeStatus":{"type":"string"},"score":{"type":"number","nullable":true}}}}}}}}},"/webhook/cielo":{"post":{"summary":"Receber webhook da Cielo","tags":["Webhooks - Cielo"],"description":"Rota pública. Cielo NÃO assina HMAC - validação via consulta Query API com credenciais do tenant. Fanout paralelo com timeout 6s para resolver o gateway dono do PaymentId.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"PaymentId":{"type":"string","format":"uuid","description":"UUID v4 do pagamento Cielo"},"ChangeType":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/rede/{accountId}":{"post":{"summary":"Receber webhook da Rede (com tenant)","tags":["Webhooks - Rede"],"description":"Rota pública recomendada. Resolve tenant pela URL, sem broadcast. Validação via consulta API com PV+Token. Rate limit 10 req/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tid":{"type":"string","description":"Transaction ID (alfanumérico 8-40 chars)"},"reference":{"type":"string","nullable":true},"returnCode":{"type":"string","nullable":true},"status":{"type":"string","nullable":true}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/rede":{"post":{"summary":"Receber webhook da Rede (legado, sem tenant)","tags":["Webhooks - Rede"],"description":"Rota legada com rate limit restrito (5 req/min). Usa fanout broadcast para descobrir o gateway dono. Preferir rota com :accountId.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tid":{"type":"string"},"reference":{"type":"string","nullable":true},"returnCode":{"type":"string","nullable":true},"status":{"type":"string","nullable":true}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"}}}}}}}}},"/webhook/dom-pagamentos":{"post":{"summary":"Receber webhook da Dom Pagamentos","tags":["Webhooks - Dom Pagamentos"],"description":"Rota pública. Payload { event, signature (JWT HS256), data }. Resolve o pedido por data.id (pagarme_charge_id), verifica JWT com o secret do tenant quando houver e consulta o status autoritativo na API da Dom.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string"},"signature":{"type":"string"},"data":{"type":"object","additionalProperties":true}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/pagseguro/{accountId}":{"post":{"summary":"Receber webhook do PagSeguro (com tenant)","tags":["Webhooks - PagSeguro"],"description":"Rota pública. Valida HMAC-SHA256 (x-pagseguro-signature). Extrai status da primeira charge do payload.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"Order ID do PagSeguro"},"reference_id":{"type":"string","nullable":true},"charges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"accountId","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"},"pedido_id":{"type":"string"},"status":{"type":"string"}}}}}}}}},"/webhook/pagseguro":{"post":{"summary":"Receber webhook do PagSeguro (legado, sem tenant)","tags":["Webhooks - PagSeguro"],"description":"Rota de compatibilidade sem tenant no path. Resolve tenant por reference_id ou fanout HMAC.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"reference_id":{"type":"string","nullable":true},"charges":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}}},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"processed":{"type":"boolean"}}}}}}}}},"/configuracoes/checkout":{"get":{"summary":"Obter configuração de checkout do tenant","tags":["Checkout - Configuração"],"description":"Retorna configuração de checkout (fluxo direto/com_carrinho, tipo de carrinho drawer/pagina). Requer role owner, manager ou super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"checkout_config":{"type":"object","properties":{"fluxo":{"type":"string","enum":["direto","com_carrinho"]},"tipo_carrinho":{"type":"string","enum":["drawer","pagina"]}}}}}}}}}},"patch":{"summary":"Atualizar configuração de checkout","tags":["Checkout - Configuração"],"description":"Atualiza a configuração de checkout do tenant. Requer role owner, manager ou super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"fluxo":{"type":"string","enum":["direto","com_carrinho"]},"tipo_carrinho":{"type":"string","enum":["drawer","pagina"]}},"required":["fluxo","tipo_carrinho"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"checkout_config":{"type":"object","properties":{"fluxo":{"type":"string"},"tipo_carrinho":{"type":"string"}}}}}}}}}}},"/consent":{"post":{"summary":"Registrar consentimento (admin)","tags":["LGPD - Consentimento"],"description":"Admin registra consentimento manual para sujeito. Append-only no ledger. Requer owner/manager.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["sujeito_tipo","sujeito_id","categoria","status","politica_versao"],"properties":{"sujeito_tipo":{"type":"string"},"sujeito_id":{"type":"string"},"categoria":{"type":"string"},"status":{"type":"string","enum":["granted","denied","withdrawn"]},"politica_versao":{"type":"string"},"motivo":{"type":"string"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/consent/audit":{"get":{"summary":"Auditoria de consentimentos","tags":["LGPD - Consentimento"],"description":"Histórico append-only de registros de consentimento do tenant. Filtros por sujeito e categoria. Requer owner/manager.","parameters":[{"schema":{"type":"string"},"in":"query","name":"sujeito_id","required":false},{"schema":{"type":"string"},"in":"query","name":"categoria","required":false},{"schema":{"type":"integer","default":100,"maximum":500},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/consent/posture":{"get":{"summary":"Postura de conformidade","tags":["LGPD - Consentimento"],"description":"Retorna postura LGPD do tenant (conservador, equilibrado, agressivo). Requer owner/manager.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Atualizar postura","tags":["LGPD - Consentimento"],"description":"Define postura de conformidade com modo, overrides, implied_consent e banner_config. Pode exigir acknowledgment.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["modo"],"properties":{"modo":{"type":"string","enum":["conservador","equilibrado","agressivo"]},"overrides":{"type":"object"},"implied_consent":{"type":"boolean"},"banner_config":{"type":"object"},"acknowledged":{"type":"boolean"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/consent":{"post":{"summary":"Registrar consentimento (storefront)","tags":["LGPD - Consentimento Público"],"description":"Registra consentimento via banner de cookies, checkout ou minha-conta. Sem JWT, tenant pelo slug.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","sujeito_tipo","sujeito_id","categoria","status","origem_canal","politica_versao"],"properties":{"tenant_slug":{"type":"string"},"sujeito_tipo":{"type":"string"},"sujeito_id":{"type":"string"},"categoria":{"type":"string"},"status":{"type":"string"},"origem_canal":{"type":"string"},"politica_versao":{"type":"string"},"metadata":{"type":"object"}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/public/consent/cookie/{cookie_id}":{"get":{"summary":"Estado de consentimento por cookie","tags":["LGPD - Consentimento Público"],"description":"Retorna mapa de categorias com status de consentimento para o cookie_id.","parameters":[{"schema":{"type":"string"},"in":"path","name":"cookie_id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/public/consent/posture/{tenant_slug}":{"get":{"summary":"Postura pública da loja","tags":["LGPD - Consentimento Público"],"description":"Retorna modo, implied_consent, banner_config e comportamento. Usado pelo storefront para configurar o banner LGPD.","parameters":[{"schema":{"type":"string"},"in":"path","name":"tenant_slug","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/config":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/subscribe":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/unsubscribe":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/dispositivos":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/dispositivos/{id}":{"patch":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/notificacoes/push/teste":{"post":{"responses":{"200":{"description":"Default Response"}}}},"/avaliacoes":{"get":{"summary":"Listar avaliações","tags":["Apps - Avaliações"],"description":"Listagem paginada de avaliações com filtros por status, nota, produto, presença de foto e busca textual. Inclui mídias com URLs assinadas.","parameters":[{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":20,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string","enum":["pendente","aprovada","rejeitada","spam"]},"in":"query","name":"status","required":false},{"schema":{"type":"integer","minimum":1,"maximum":5},"in":"query","name":"nota","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"string","enum":["true","false"]},"in":"query","name":"com_foto","required":false},{"schema":{"type":"string"},"in":"query","name":"q","required":false,"description":"Busca por título ou texto"}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/avaliacoes/metricas":{"get":{"summary":"Métricas do app de avaliações","tags":["Apps - Avaliações"],"description":"Dashboard com totais (aprovadas, pendentes, rejeitadas), média geral, distribuição por nota, taxa de resposta, conversão de lembretes e 5 avaliações mais recentes.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/avaliacoes/config":{"get":{"summary":"Ler configuração do app de avaliações","tags":["Apps - Avaliações"],"description":"Retorna configuração do app (lembretes, incentivos, auto-approve, moderação IA). Se não existe, retorna defaults.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Salvar configuração do app de avaliações","tags":["Apps - Avaliações"],"description":"Upsert da configuração do app. Campos: lembrete, incentivo (texto/foto/video %), auto_approve, moderar_com_ia, etc.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/avaliacoes/{id}":{"get":{"summary":"Detalhe da avaliação","tags":["Apps - Avaliações"],"description":"Retorna avaliação com mídias (URLs assinadas), dados do cliente e do produto.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/avaliacoes/{id}/status":{"patch":{"summary":"Moderar avaliação (aprovar/rejeitar)","tags":["Apps - Avaliações"],"description":"Altera status da avaliação. Se aprovada, gera cupom de incentivo (se configurado) e emite evento review_approved.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["pendente","aprovada","rejeitada","spam"]},"motivo":{"type":"string","description":"Motivo da moderação"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/avaliacoes/{id}/resposta":{"post":{"summary":"Responder avaliação","tags":["Apps - Avaliações"],"description":"Lojista adiciona resposta pública a uma avaliação.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["texto"],"properties":{"texto":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover resposta da avaliação","tags":["Apps - Avaliações"],"description":"Remove a resposta do lojista de uma avaliação.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/avaliacoes":{"get":{"summary":"Listar avaliações aprovadas por produto","tags":["Apps - Avaliações (Público)"],"description":"Retorna avaliações aprovadas de um produto com paginação e ordenação (recentes, úteis, maior/menor nota). Mídias com URLs assinadas. Rate limit: 30/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true},{"schema":{"type":"integer","default":1},"in":"query","name":"page","required":false},{"schema":{"type":"integer","default":10,"maximum":50},"in":"query","name":"limit","required":false},{"schema":{"type":"string","enum":["recentes","uteis","maior_nota","menor_nota","nota_alta","nota_baixa"],"default":"recentes"},"in":"query","name":"sort","required":false}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar avaliação","tags":["Apps - Avaliações (Público)"],"description":"Cliente final cria avaliação de produto. Verifica compra verificada, duplicidade, limites de mídia (5 fotos + 1 vídeo). Suporta auto-moderação IA. Rate limit: 5/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","produto_id","nota"],"properties":{"tenant_slug":{"type":"string"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"pedido_id":{"type":["string","null"],"format":"uuid"},"cliente_id":{"type":["string","null"],"format":"uuid"},"nota":{"type":"integer","minimum":1,"maximum":5},"titulo":{"type":"string"},"texto":{"type":"string"},"anonimo":{"type":"boolean","default":false},"midias":{"type":"array","maxItems":6,"items":{"type":"object","properties":{"tipo":{"type":"string","enum":["foto","video"]},"path":{"type":"string"}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response"}}}},"/public/avaliacoes/resumo":{"get":{"summary":"Resumo de avaliações do produto","tags":["Apps - Avaliações (Público)"],"description":"Retorna média, total e distribuição por nota (1-5) das avaliações aprovadas de um produto.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"media":{"type":["null","number"]},"total":{"type":"integer"},"distribuicao":{"type":"object","additionalProperties":{"type":"integer"}}}}}}}}}},"/public/avaliacoes/{id}/util":{"post":{"summary":"Marcar avaliação como útil","tags":["Apps - Avaliações (Público)"],"description":"Voto de utilidade por cookie_id. Idempotente via ON CONFLICT. Recalcula util_count. Rate limit: 30/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["cookie_id"],"properties":{"cookie_id":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}},"/public/avaliacoes/galeria":{"get":{"summary":"Galeria de mídias aprovadas","tags":["Apps - Avaliações (Público)"],"description":"Retorna fotos e vídeos de avaliações aprovadas do tenant. Usado para UGC gallery no storefront.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"integer","default":20,"maximum":50},"in":"query","name":"limit","required":false}],"responses":{"200":{"description":"Default Response"}}}},"/public/avaliacoes/elegivel":{"get":{"summary":"Verificar elegibilidade para avaliar","tags":["Apps - Avaliações (Público)"],"description":"Verifica se o cliente pode avaliar um produto de um pedido (status válido, sem duplicata).","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"pedido_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"cliente_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"elegivel":{"type":"boolean"},"motivo":{"type":"string"}}}}}}}}},"/public/avaliacoes/upload-url":{"post":{"summary":"Gerar URL de upload assinada","tags":["Apps - Avaliações (Público)"],"description":"Gera signed upload URL para foto ou vídeo de avaliação. Valida que a avaliação pertence ao tenant. Rate limit: 10/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","tipo","extensao","avaliacao_id"],"properties":{"tenant_slug":{"type":"string"},"tipo":{"type":"string","enum":["foto","video"]},"extensao":{"type":"string"},"avaliacao_id":{"type":"string","format":"uuid"},"ordem":{"type":"integer"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"upload_url":{"type":"string"},"path":{"type":"string"},"token":{"type":"string"}}}}}}}}},"/public/avaliacoes/{id}/midias":{"post":{"summary":"Confirmar mídias enviadas","tags":["Apps - Avaliações (Público)"],"description":"Registra as fotos/vídeo já enviados ao storage. Só aceita arquivos que existem na pasta da própria avaliação, uma única vez e até 2h após a criação.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","midias"],"properties":{"tenant_slug":{"type":"string"},"midias":{"type":"array","minItems":1,"maxItems":6,"items":{"type":"object","required":["tipo","path"],"properties":{"tipo":{"type":"string","enum":["foto","video"]},"path":{"type":"string"},"ordem":{"type":"integer"},"largura":{"type":"integer"},"altura":{"type":"integer"},"duracao_segundos":{"type":"integer"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"registradas":{"type":"integer"}}}}}}}}},"/quiz":{"get":{"summary":"Listar quizzes","tags":["Apps - Quiz"],"description":"Lista quizzes do tenant com contagem de respostas (iniciadas e concluídas).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar quiz","tags":["Apps - Quiz"],"description":"Cria um quiz em rascunho a partir do nome (slug único por tenant). Aceita definição inicial opcional.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"definicao":{"type":"object","additionalProperties":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/picker":{"get":{"summary":"Quizzes para o picker do editor","tags":["Apps - Quiz"],"description":"Lista enxuta (id, nome, slug, status) para o campo quiz_picker do editor de tema.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}":{"get":{"summary":"Detalhe do quiz","tags":["Apps - Quiz"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar quiz","tags":["Apps - Quiz"],"description":"Atualiza nome, definição (draft do builder) ou status. Publicar usa POST /quiz/:id/publicar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"definicao":{"type":"object","additionalProperties":true},"status":{"type":"string","enum":["rascunho","publicado","pausado"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir quiz","tags":["Apps - Quiz"],"description":"Remove o quiz e suas respostas (cascade).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}/publicar":{"post":{"summary":"Publicar quiz","tags":["Apps - Quiz"],"description":"Copia a definição draft para o snapshot publicado (servido no storefront) e ativa o quiz.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}/duplicar":{"post":{"summary":"Duplicar quiz","tags":["Apps - Quiz"],"description":"Cria uma cópia do quiz em rascunho (nova definição draft; snapshot publicado não é copiado).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}/analytics":{"get":{"summary":"Analytics do quiz","tags":["Apps - Quiz"],"description":"Funil (views/starts/steps/completes), leads, distribuição de respostas, timeline, top produtos e receita atribuída (quiz_purchase server-side). Cache 60s.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}/respostas":{"get":{"summary":"Respostas do quiz","tags":["Apps - Quiz"],"description":"Lista respostas (leads) do quiz, paginação por cursor (before = ISO de iniciado_em).","parameters":[{"schema":{"type":"integer","default":50,"maximum":200},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"before","required":false},{"schema":{"type":"string","enum":["iniciado","concluido"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/quiz/{id}/respostas.csv":{"get":{"summary":"Exportar respostas (CSV)","tags":["Apps - Quiz"],"description":"Exporta as respostas do quiz em CSV (até 5000 linhas, mais recentes primeiro).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/quiz/{slug}":{"get":{"summary":"Quiz publicado (storefront)","tags":["Apps - Quiz (Público)"],"description":"Retorna o quiz publicado sem votos/tags das opções. 404 se app inativo ou quiz não publicado. Rate limit: 60/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/public/quiz/{id}/iniciar":{"post":{"summary":"Iniciar resposta do quiz","tags":["Apps - Quiz (Público)"],"description":"Cria o registro de resposta (status iniciado) para medir drop-off. Rate limit: 30/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain"],"properties":{"subdomain":{"type":"string"},"anonymous_id":{"type":["string","null"]},"sessao_id":{"type":["string","null"]}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"resposta_id":{"type":"string"}}}}}}}}},"/public/quiz/{id}/responder":{"post":{"summary":"Concluir quiz e obter recomendações","tags":["Apps - Quiz (Público)"],"description":"Valida as respostas contra a definição publicada, roda o motor de recomendação, persiste a resposta, resolve o cliente (logado ou capturado no gate), grava zero-party data e emite quiz_completed. Rate limit: 20/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain","respostas"],"properties":{"subdomain":{"type":"string"},"resposta_id":{"type":["string","null"]},"anonymous_id":{"type":["string","null"]},"sessao_id":{"type":["string","null"]},"respostas":{"type":"array","maxItems":60,"items":{"type":"object","required":["pergunta_id"],"additionalProperties":true,"properties":{"pergunta_id":{"type":"string"},"opcao_ids":{"type":"array","maxItems":30,"items":{"type":"string"}},"valor":{"anyOf":[{"type":"string","maxLength":500},{"type":"number"},{"type":"null"}]}}}},"contato":{"type":["object","null"],"additionalProperties":true,"properties":{"nome":{"type":["string","null"]},"email":{"type":["string","null"]},"telefone":{"type":["string","null"]},"aceitou_marketing":{"type":["boolean","null"]},"politica_versao":{"type":["string","null"]}}},"utm":{"type":["object","null"],"additionalProperties":false,"properties":{"utm_source":{"type":"string","maxLength":200},"utm_medium":{"type":"string","maxLength":200},"utm_campaign":{"type":"string","maxLength":200},"utm_term":{"type":"string","maxLength":200},"utm_content":{"type":"string","maxLength":200},"source":{"type":"string","maxLength":200},"medium":{"type":"string","maxLength":200},"campaign":{"type":"string","maxLength":200},"term":{"type":"string","maxLength":200},"content":{"type":"string","maxLength":200}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/order-bump/regras":{"get":{"summary":"Listar regras de order bump","tags":["Apps - Order Bump"],"description":"Lista as regras do tenant com métricas resumidas dos últimos 30 dias (impressões, aceites, remoções, taxa de aceite).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Criar regra de order bump","tags":["Apps - Order Bump"],"description":"Cria uma regra de oferta no checkout. Desconto sempre calculado e travado server-side no aceite.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"ativo":{"type":"boolean"},"prioridade":{"type":"integer","minimum":0,"maximum":100000},"gatilho_tipo":{"type":"string","enum":["todos","produtos","categorias"]},"gatilho_ids":{"type":"array","maxItems":200,"items":{"type":"string","format":"uuid"}},"valor_min_centavos":{"type":["integer","null"],"minimum":0},"valor_max_centavos":{"type":["integer","null"],"minimum":0},"primeira_compra":{"type":"boolean"},"canal":{"type":"string","enum":["ambos","b2c","b2b"]},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"]},"tipo_desconto":{"type":"string","enum":["percentual","valor","preco_fixo"]},"valor_desconto":{"type":"integer","minimum":0},"titulo":{"type":"string","minLength":1,"maxLength":160},"subtitulo":{"type":["string","null"],"maxLength":240},"badge":{"type":["string","null"],"maxLength":40},"validade_inicio":{"type":["string","null"]},"validade_fim":{"type":["string","null"]}},"required":["nome","titulo","produto_id","tipo_desconto","valor_desconto"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/order-bump/regras/{id}":{"get":{"summary":"Detalhe da regra","tags":["Apps - Order Bump"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"patch":{"summary":"Atualizar regra","tags":["Apps - Order Bump"],"description":"Atualização parcial. O estado combinado (atual + alterações) é revalidado por inteiro.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"ativo":{"type":"boolean"},"prioridade":{"type":"integer","minimum":0,"maximum":100000},"gatilho_tipo":{"type":"string","enum":["todos","produtos","categorias"]},"gatilho_ids":{"type":"array","maxItems":200,"items":{"type":"string","format":"uuid"}},"valor_min_centavos":{"type":["integer","null"],"minimum":0},"valor_max_centavos":{"type":["integer","null"],"minimum":0},"primeira_compra":{"type":"boolean"},"canal":{"type":"string","enum":["ambos","b2c","b2b"]},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"]},"tipo_desconto":{"type":"string","enum":["percentual","valor","preco_fixo"]},"valor_desconto":{"type":"integer","minimum":0},"titulo":{"type":"string","minLength":1,"maxLength":160},"subtitulo":{"type":["string","null"],"maxLength":240},"badge":{"type":["string","null"],"maxLength":40},"validade_inicio":{"type":["string","null"]},"validade_fim":{"type":["string","null"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Excluir regra","tags":["Apps - Order Bump"],"description":"Remove a regra. Itens de bump já aceitos em carrinhos abertos mantêm o preço travado (honrado no checkout).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/order-bump/regras/{id}/duplicar":{"post":{"summary":"Duplicar regra","tags":["Apps - Order Bump"],"description":"Cria uma cópia da regra. A cópia nasce inativa para não duplicar a oferta no checkout imediatamente.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/order-bump/analytics":{"get":{"summary":"Analytics do order bump","tags":["Apps - Order Bump"],"description":"Impressões/aceites/remoções (tracking bump_view/bump_accept/bump_remove por regra) + receita incremental (pedido_itens com dados_extras.bump em pedidos pagos do período) + AOV com × sem bump. Cache 60s.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/order-bump/ofertas":{"get":{"summary":"Ofertas de order bump para o carrinho atual","tags":["Apps - Order Bump (Público)"],"description":"Avalia as regras ativas contra o rascunho da sessão (gatilho, condições, validade, estoque, produto ausente do carrinho) e retorna até N ofertas priorizadas com preços calculados no server. N = config_global.max_ofertas (1-2, default 1). Rate limit: 30/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":true},{"schema":{"type":"string"},"in":"query","name":"session_token","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/order-bump/aceitar":{"post":{"summary":"Aceitar oferta de order bump","tags":["Apps - Order Bump (Público)"],"description":"REVALIDA a regra contra o carrinho no server, calcula o preço travado e insere o item (quantidade 1) com dados_extras.bump. Retorna o carrinho atualizado no mesmo shape do GET /cart. Erros de domínio 422: carrinho_nao_encontrado, carrinho_vazio, oferta_ja_aceita, oferta_indisponivel. Rate limit: 15/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain","session_token","regra_id"],"properties":{"subdomain":{"type":"string"},"session_token":{"type":"string"},"regra_id":{"type":"string","format":"uuid"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/kit":{"get":{"summary":"Listar kits","tags":["Apps - Monte seu Kit"],"description":"Lista os kits do tenant com a contagem de kits montados (pedidos pagos que contêm itens do kit).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"post":{"summary":"Criar kit","tags":["Apps - Monte seu Kit"],"description":"Cria um kit em rascunho a partir do nome (slug único por tenant). Aceita definição inicial opcional.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome"],"properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"definicao":{"type":"object","additionalProperties":true}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/kit/picker":{"get":{"summary":"Kits para o picker do editor","tags":["Apps - Monte seu Kit"],"description":"Lista enxuta (id, nome, slug, status) para o campo kit_picker do editor de tema.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/kit/analytics":{"get":{"summary":"Analytics do Monte seu Kit","tags":["Apps - Monte seu Kit"],"description":"Kits montados, ticket médio, receita, itens/kit médio, timeline por dia e produtos mais incluídos — agrega pedido_itens com dados_extras.kit em pedidos pagos do período. Cache 60s.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/kit/{id}":{"get":{"summary":"Detalhe do kit","tags":["Apps - Monte seu Kit"],"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar kit","tags":["Apps - Monte seu Kit"],"description":"Atualiza nome, definição (draft do builder) ou status. Publicar usa POST /kit/:id/publicar.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nome":{"type":"string","minLength":1,"maxLength":120},"definicao":{"type":"object","additionalProperties":true},"status":{"type":"string","enum":["rascunho","publicado","pausado"]}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Excluir kit","tags":["Apps - Monte seu Kit"],"description":"Remove o kit. Itens de kit já no carrinho mantêm o preço travado (honrado no checkout).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/kit/{id}/publicar":{"post":{"summary":"Publicar kit","tags":["Apps - Monte seu Kit"],"description":"Valida a definição (>=1 elegível, >=1 faixa, min<=max) e copia o draft para o snapshot publicado (servido no storefront), ativando o kit.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/kit/{id}/duplicar":{"post":{"summary":"Duplicar kit","tags":["Apps - Monte seu Kit"],"description":"Cria uma cópia do kit em rascunho (nova definição draft; snapshot publicado não é copiado).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/public/kit/{slug}":{"get":{"summary":"Kit publicado (storefront)","tags":["Apps - Monte seu Kit (Público)"],"description":"Retorna o kit publicado (definicao_publicada) para o montador. 404 se app inativo ou kit não publicado. Aceita UUID ou slug. Rate limit: 60/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":true},{"schema":{"type":"string"},"in":"path","name":"slug","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/kit/aceitar":{"post":{"summary":"Adicionar kit montado ao carrinho","tags":["Apps - Monte seu Kit (Público)"],"description":"REVALIDA elegibilidade + min/max dos itens contra a definição publicada, resolve a faixa pela qtd total, calcula o preço travado por item no server e insere N pedido_itens (dados_extras.kit) no rascunho da sessão. Retorna o carrinho no mesmo shape do GET /cart. Erros 422: kit_indisponivel, kit_min_itens, kit_max_itens, produto_nao_elegivel, produto_sem_estoque, produto_nao_compravel. Cliente NUNCA envia preço. Rate limit: 15/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain","session_token","kit_slug","itens"],"properties":{"subdomain":{"type":"string"},"session_token":{"type":"string"},"kit_slug":{"type":"string"},"itens":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","required":["produto_id"],"additionalProperties":true,"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"]},"quantidade":{"type":"integer","minimum":1,"maximum":999}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/grade/{produto_id}":{"get":{"summary":"Definição da grade e disponibilidade por célula","tags":["Apps - Compra em Grade (Público)"],"description":"Devolve os eixos de variação do produto, as células (variação + vínculo de eixo + preço + disponibilidade) e a definição de limites. Células sem vínculo de eixo vêm marcadas como `orfa` e combinações com mais de uma variação vêm em `colisoes`, para o front decidir o render em vez de quebrar a matriz. 404 quando o app está inativo ou o produto não tem grade configurada.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produto_id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/grade/aceitar":{"post":{"summary":"Adicionar a grade montada ao carrinho","tags":["Apps - Compra em Grade (Público)"],"description":"REVALIDA no servidor: variação pertence ao produto e está ativa, limite da caixa (exato/faixa/múltiplo), limite por célula, modo de venda, e estoque agregado por célula. Calcula a faixa pela quantidade total, trava o preço por unidade e insere N pedido_itens (dados_extras.grade) no rascunho da sessão. Retorna o carrinho no shape do GET /cart. Erros 422: grade_indisponivel, caixa_vazia, caixa_incompleta, caixa_excedida, caixa_multiplo, item_min, item_max, item_multiplo, variacao_invalida, variacao_sem_preco, produto_nao_compravel, celula_sem_estoque (com a lista `celulas`). Cliente NUNCA envia preço. Rate limit: 15/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["subdomain","session_token","produto_id","itens"],"properties":{"subdomain":{"type":"string"},"session_token":{"type":"string"},"produto_id":{"type":"string","format":"uuid"},"itens":{"type":"array","minItems":1,"maxItems":200,"items":{"type":"object","required":["variacao_id"],"additionalProperties":true,"properties":{"variacao_id":{"type":"string","format":"uuid"},"quantidade":{"type":"integer","minimum":1,"maximum":9999}}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/avise/interesses":{"get":{"summary":"Listar interesses de reposição","tags":["Apps - Avise-me"],"description":"Fila de demanda do tenant com nome do produto/variação e do contato. Filtros por status e produto. Paginação por cursor (before = criado_em do último item).","parameters":[{"schema":{"type":"string","enum":["pendente","notificado","convertido","cancelado"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":false},{"schema":{"type":"integer","default":30,"minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"before","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/avise/analytics":{"get":{"summary":"Analytics do avise-me","tags":["Apps - Avise-me"],"description":"Demanda registrada, notificados, convertidos e receita recuperada (pedidos pagos com o produto após o notificado_em, na janela), taxa de recuperação, top produtos mais aguardados e timeline diária.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/avise/notificar-agora":{"post":{"summary":"Notificar interessados de um SKU agora","tags":["Apps - Avise-me"],"description":"Reusa a trilha do cron: reconfirma a disponibilidade real do produto/variação e notifica os interessados pendentes (idempotente — nunca notifica 2x).","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id"],"additionalProperties":false,"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/avise/interesses/{id}":{"delete":{"summary":"Cancelar interesse de reposição","tags":["Apps - Avise-me"],"description":"Marca o interesse como cancelado (não recebe mais aviso).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/avise/registrar":{"post":{"summary":"Registrar interesse de reposição (back in stock)","tags":["Apps - Avise-me (Público)"],"description":"Cliente final pede para ser avisado quando o produto/variação voltar ao estoque. Idempotente: o mesmo contato não registra o mesmo SKU duas vezes (retorna já_registrado). Resolve/cria o cliente (best-effort), registra consentimento de marketing quando aceito e emite generate_lead. Rate limit: 20/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","produto_id"],"additionalProperties":false,"properties":{"tenant_slug":{"type":"string"},"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"email":{"type":["string","null"],"maxLength":200},"telefone":{"type":["string","null"],"maxLength":30},"nome":{"type":["string","null"],"maxLength":120},"aceitou_marketing":{"type":["boolean","null"]},"politica_versao":{"type":["string","null"],"maxLength":40},"anonymous_id":{"type":["string","null"],"maxLength":100}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/avise/status":{"get":{"summary":"Verificar se o contato já está inscrito no aviso de reposição","tags":["Apps - Avise-me (Público)"],"description":"Retorna se o e-mail/telefone informado já tem interesse pendente para o produto/variação. Rate limit: 60/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"tenant_slug","required":true},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true},{"schema":{"type":["string","null"],"format":"uuid"},"in":"query","name":"variacao_id","required":false},{"schema":{"type":["string","null"]},"in":"query","name":"email","required":false},{"schema":{"type":["string","null"]},"in":"query","name":"telefone","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/provador/modelagem/{produtoId}":{"get":{"summary":"Modelagem de um produto","tags":["Apps - Provador Virtual"],"description":"Retorna como a peça foi cortada (tipo, grade, elasticidade, caimento) e a tabela de medidas por tamanho e ponto anatômico. Produto sem modelagem cadastrada devolve modelagem null, que não é erro: é o estado inicial de todo produto.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"put":{"summary":"Salvar a modelagem de um produto","tags":["Apps - Provador Virtual"],"description":"Cria ou atualiza a modelagem e SUBSTITUI a tabela de medidas inteira pelo conjunto enviado. A troca das medidas é feita como transação lógica: se o insert do conjunto novo falhar, o conjunto anterior é restaurado, para o produto nunca ficar sem tabela de medidas por causa de um erro de gravação.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo_peca"],"additionalProperties":false,"properties":{"tipo_peca":{"type":"string"},"grade":{"type":["string","null"]},"elasticidade":{"type":["string","null"]},"caimento_padrao":{"type":["string","null"]},"modelo_altura_cm":{"type":["number","null"]},"modelo_tamanho":{"type":["string","null"],"maxLength":40},"fonte":{"type":["string","null"]},"observacao":{"type":["string","null"],"maxLength":500},"medidas":{"type":"array","maxItems":400,"items":{"type":"object","required":["tamanho_label","ponto","valor_cm"],"additionalProperties":true,"properties":{"opcao_valor_id":{"type":["string","null"],"format":"uuid"},"tamanho_label":{"type":"string","maxLength":40},"posicao":{"type":["integer","null"]},"ponto":{"type":"string"},"valor_cm":{"type":"number"}}}}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"delete":{"summary":"Remover a modelagem de um produto","tags":["Apps - Provador Virtual"],"description":"Apaga a modelagem e, por cascata, a tabela de medidas. O produto volta a ficar sem provador na página.","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"produtoId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/provador/analytics":{"get":{"summary":"Analytics do provador virtual","tags":["Apps - Provador Virtual"],"description":"Consultas, perfis, uso no carrinho, aderência à recomendação e a taxa de devolução por tamanho errado entre pedidos que passaram pelo provador e pedidos que não passaram. A comparação é feita só sobre produtos que têm modelagem, que são os únicos onde o provador existia como opção. Sem massa de dados, as taxas voltam zeradas em vez de estimadas.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/provador/analytics/tamanhos":{"get":{"summary":"Tamanhos mais buscados e venda perdida por peça","tags":["Apps - Provador Virtual"],"description":"Curva de tamanhos recomendados por peça (produto agrupado soma no grupo) e as consultas em que o tamanho recomendado estava sem estoque, com o valor procurado em centavos. Consultas anteriores à migration 378 não sabem o estoque e não contam como perdidas.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/provador/produtos":{"get":{"summary":"Produtos com e sem modelagem","tags":["Apps - Provador Virtual"],"description":"Lista os produtos do tenant com a marcação de quem já tem tabela de medidas e quantos tamanhos estão medidos. É a fila de trabalho da tela de conteúdo do app. Aceita busca por nome ou SKU, filtro por situação da modelagem e paginação.","parameters":[{"schema":{"type":"string","maxLength":120},"in":"query","name":"q","required":false},{"schema":{"type":"string","enum":["todos","com","sem"],"default":"todos"},"in":"query","name":"modelagem","required":false},{"schema":{"type":"string","enum":["todos","sim","nao"],"default":"sim"},"in":"query","name":"ativo","required":false},{"schema":{"type":"integer","default":30,"minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"integer","default":0,"minimum":0},"in":"query","name":"offset","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/provador/recomendar":{"post":{"summary":"Recomendar tamanho para um produto","tags":["Apps - Provador Virtual (Público)"],"description":"Monta a grade real do produto (tamanhos à venda + medidas da peça), aplica o viés aprendido com as devoluções por tamanho errado quando a loja liga essa opção, roda o motor e registra a consulta. Devolve a recomendação com o mapa de caimento por região e o consulta_id, que a UI usa depois para informar o tamanho de fato escolhido. Rate limit: 30/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["produto_id","perfil"],"additionalProperties":false,"properties":{"subdomain":{"type":["string","null"]},"account_id":{"type":["string","null"],"format":"uuid"},"produto_id":{"type":"string","format":"uuid"},"anonymous_id":{"type":["string","null"],"maxLength":100},"session_token":{"type":["string","null"],"maxLength":200},"salvar_perfil":{"type":["boolean","null"]},"perfil_id":{"type":["string","null"]},"perfil_nome":{"type":["string","null"],"maxLength":60},"perfil_novo":{"type":["boolean","null"]},"perfil":{"type":"object","additionalProperties":true,"properties":{"grade":{"type":"string"},"altura_cm":{"type":"number"},"peso_kg":{"type":"number"},"idade":{"type":["integer","null"]},"formato_corpo":{"type":["string","null"]},"preferencia_caimento":{"type":["string","null"]},"medidas_informadas":{"type":["object","null"],"additionalProperties":true}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"grupo_id":{"type":["null","string"]},"avaliacoes":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"produto_id":{"type":"string"},"produto_slug":{"type":["null","string"]}}}}}}}}}}}},"/public/provador/tem-modelagem":{"get":{"summary":"O produto tem tabela de medidas para o provador","tags":["Apps - Provador Virtual (Público)"],"description":"Diz se o provador tem o que recomendar neste produto: modelagem própria ou, em produto agrupado, a do irmão (a mesma regra do recomendar). A PDP usa para mostrar o botão só onde há tabela. Resposta cacheável por 60 s. Rate limit: 120/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"produto_id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","required":["tem_modelagem"],"properties":{"tem_modelagem":{"type":"boolean"}}}}}}}}},"/public/provador/perfil":{"get":{"summary":"Perfil corporal do cliente logado ou do visitante","tags":["Apps - Provador Virtual (Público)"],"description":"Retorna o perfil corporal do cliente logado (header x-user-id) ou do anonymous_id informado. Quando os dois chegam juntos, o perfil criado como visitante é adotado pelo cliente antes da leitura. Rate limit: 60/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","maxLength":100},"in":"query","name":"anonymous_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"post":{"summary":"Salvar o perfil corporal","tags":["Apps - Provador Virtual (Público)"],"description":"Cria ou atualiza o perfil do cliente logado ou do visitante anônimo. Grava também as medidas estimadas e a versão do estimador que as calculou. Rate limit: 20/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["perfil"],"additionalProperties":false,"properties":{"subdomain":{"type":["string","null"]},"account_id":{"type":["string","null"],"format":"uuid"},"anonymous_id":{"type":["string","null"],"maxLength":100},"perfil_id":{"type":["string","null"]},"nome":{"type":["string","null"],"maxLength":60},"novo":{"type":["boolean","null"]},"perfil":{"type":"object","additionalProperties":true,"properties":{"grade":{"type":"string"},"altura_cm":{"type":"number"},"peso_kg":{"type":"number"},"idade":{"type":["integer","null"]},"formato_corpo":{"type":["string","null"]},"preferencia_caimento":{"type":["string","null"]},"medidas_informadas":{"type":["object","null"],"additionalProperties":true}}}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/provador/perfis":{"get":{"summary":"Perfis de medidas do cliente ou do visitante","tags":["Apps - Provador Virtual (Público)"],"description":"Lista os perfis (eu, cônjuge, filhos...) do cliente logado (x-user-id) ou do anonymous_id, do usado por último para o mais antigo, até 10. Com os dois, os perfis do visitante são adotados pelo cliente antes. Rate limit: 60/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","maxLength":100},"in":"query","name":"anonymous_id","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/provador/perfil/{id}":{"delete":{"summary":"Remover um perfil de medidas","tags":["Apps - Provador Virtual (Público)"],"description":"Apaga o perfil do dono da sessão (cliente logado ou anonymous_id). Perfil de outra pessoa responde 404. As consultas antigas ficam, sem o perfil. Rate limit: 20/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"account_id","required":false},{"schema":{"type":"string","maxLength":100},"in":"query","name":"anonymous_id","required":false},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/provador/consulta/{id}":{"patch":{"summary":"Registrar o tamanho escolhido e a ida ao carrinho","tags":["Apps - Provador Virtual (Público)"],"description":"Fecha o ciclo da recomendação: qual tamanho a pessoa escolheu de fato e se o item foi para o carrinho. É com isto que se mede aderência, ou seja, se o motor está calibrado. Em produto agrupado, `produto_id` é o membro do tamanho escolhido: a consulta passa a apontar para ele, que é o produto que vai ao pedido (atribuição da 366 e analytics). Só vale membro do mesmo grupo e da mesma loja do produto da consulta. Rate limit: 60/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"subdomain":{"type":["string","null"]},"account_id":{"type":["string","null"],"format":"uuid"},"tamanho_escolhido":{"type":["string","null"],"maxLength":40},"adicionou_carrinho":{"type":["boolean","null"]},"produto_id":{"type":["string","null"],"format":"uuid"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/cobertura/demanda":{"get":{"summary":"Demanda represada por região (CEP sem cobertura de entrega)","tags":["Frete - Cobertura"],"description":"Agrupa a lista de espera por cidade e bairro, somando pessoas e o valor de carrinho barrado. Ordenado por valor barrado desc: o topo da lista é a próxima faixa de CEP que vale abrir. Considera apenas interesses pendentes. Cada região traz `ja_atendida`: as regras de frete de hoje já cobrem aquele CEP, então essas pessoas podem ser avisadas.","parameters":[{"schema":{"type":"integer","default":90,"minimum":1,"maximum":730},"in":"query","name":"dias","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/cobertura/interesses":{"get":{"summary":"Listar quem pediu aviso de cobertura de entrega","tags":["Frete - Cobertura"],"description":"Fila do tenant com CEP, contato e valor do carrinho barrado, para atendimento ativo. Contém PII: restrito a owner, manager e super_admin. Paginação por cursor (before = criado_em do último item).","parameters":[{"schema":{"type":"string","enum":["pendente","notificado","descartado"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","maxLength":8},"in":"query","name":"cep_prefixo","required":false},{"schema":{"type":"integer","default":30,"minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"before","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/cobertura/registrar":{"post":{"summary":"Entrar na lista de espera de entrega para um CEP","tags":["Frete - Cobertura (Público)"],"description":"Cliente final pede aviso quando a loja passar a entregar no CEP dele. Chamado pelo checkout quando nenhuma regra de frete atendeu o CEP. Idempotente: o mesmo contato não entra duas vezes na fila do mesmo CEP (retorna ja_registrado). Guarda o valor do carrinho para o lojista medir receita perdida por região. Rate limit: 20/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","cep"],"additionalProperties":false,"properties":{"tenant_slug":{"type":"string"},"cep":{"type":"string","maxLength":20},"uf":{"type":["string","null"],"maxLength":2},"cidade":{"type":["string","null"],"maxLength":120},"bairro":{"type":["string","null"],"maxLength":120},"email":{"type":["string","null"],"maxLength":200},"telefone":{"type":["string","null"],"maxLength":30},"nome":{"type":["string","null"],"maxLength":120},"valor_carrinho_centavos":{"type":["integer","null"],"minimum":0,"maximum":100000000},"aceitou_marketing":{"type":["boolean","null"]},"politica_versao":{"type":["string","null"],"maxLength":40},"anonymous_id":{"type":["string","null"],"maxLength":100}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/frete/localizacao/cep":{"post":{"summary":"CEP pela localização do aparelho","tags":["Logística - Frete Compat"],"description":"Converte a coordenada do navegador em CEP e endereço (OpenStreetMap/Nominatim + ViaCEP). Sem login. A coordenada não é gravada nem registrada em log; o resultado fica em cache por 30 dias (coordenada arredondada em 4 casas). Consulta ao Nominatim limitada a 1 por segundo na plataforma. cep null com opcoes = a rua tem vários CEPs e o cliente escolhe. Rate limit: 10/min por IP.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["lat","lng"],"additionalProperties":false,"properties":{"lat":{"type":"number","description":"Latitude do aparelho"},"lng":{"type":"number","description":"Longitude do aparelho"}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"cep":{"type":["null","string"],"description":"8 dígitos; null quando há opcoes"},"logradouro":{"type":"string"},"bairro":{"type":"string"},"cidade":{"type":"string"},"uf":{"type":"string"},"precisao":{"type":"string","enum":["cep","rua"]},"opcoes":{"type":"array","maxItems":10,"items":{"type":"object","properties":{"cep":{"type":"string"},"logradouro":{"type":"string"},"bairro":{"type":"string"},"complemento":{"type":"string"}}}}}}}}},"404":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"erro":{"type":"string"}}}}}},"422":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"erro":{"type":"string"}}}}}},"503":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"erro":{"type":"string"}}}}}}}}},"/public/dominio/apex":{"get":{"responses":{"200":{"description":"Default Response"}}}},"/public/orcamento/solicitar":{"post":{"summary":"Solicitar orçamento a partir da loja","tags":["Apps - Catálogo e Orçamento (Público)"],"description":"Cliente final envia a lista de itens em modo orçamento. Cria um pedido rascunho (Shopify Draft Order) com origem=\"orcamento\" para o lojista precificar e devolver o link de pagamento. Preço vem do catálogo no servidor, nunca do payload. Rate limit: 10/min.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tenant_slug","itens","nome","telefone"],"additionalProperties":false,"properties":{"tenant_slug":{"type":"string"},"itens":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"object","required":["produto_id","quantidade"],"additionalProperties":false,"properties":{"produto_id":{"type":"string","format":"uuid"},"variacao_id":{"type":["string","null"],"format":"uuid"},"quantidade":{"type":"integer","minimum":1,"maximum":9999}}}},"nome":{"type":"string","maxLength":120},"telefone":{"type":"string","maxLength":30},"email":{"type":["string","null"],"maxLength":200},"cnpj":{"type":["string","null"],"maxLength":20},"observacao":{"type":["string","null"],"maxLength":1000},"anonymous_id":{"type":["string","null"],"maxLength":100}}}}},"required":true},"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/prova-social/recentes":{"get":{"summary":"Vendas recentes anonimizadas (sales pop)","tags":["Apps - Prova Social (Público)"],"description":"Pool de pedidos REAIS pagos na janela configurada, anonimizado server-side (nome abreviado, cidade opcional, tempo relativo). Nunca retorna valores, quantidades nem identificadores de cliente. Pool com menos de 3 vendas → lista vazia (loja de baixo volume em loop parece fake). App inativo → 404. Cache de 60s por tenant+config. Rate limit: 30/min.","parameters":[{"schema":{"type":"string"},"in":"query","name":"subdomain","required":true},{"schema":{"type":"integer","minimum":1,"maximum":30},"in":"query","name":"limit","required":false}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"vendas":{"type":"array","items":{"type":"object","additionalProperties":true}},"total":{"type":"integer"},"config":{"type":"object","additionalProperties":true}}}}}}}}},"/pre-venda/produtos":{"get":{"summary":"Listar produtos em pré-venda","tags":["Apps - Pré-venda"],"description":"Produtos com preorder=true do tenant, com data prevista de envio, limite e a contagem de unidades já pré-vendidas (itens com dados_extras.preorder em pedidos não cancelados).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pre-venda/pedidos":{"get":{"summary":"Listar pedidos de pré-venda","tags":["Apps - Pré-venda"],"description":"Pedidos com a tag \"pre-venda\" (têm ao menos um item de pré-venda), com os itens de pré-venda e o status de chegada (notificado quando o cliente já foi avisado). Paginação por cursor (before = created_at do último item).","parameters":[{"schema":{"type":"string"},"in":"query","name":"status","required":false},{"schema":{"type":"integer","default":30,"minimum":1,"maximum":100},"in":"query","name":"limit","required":false},{"schema":{"type":"string"},"in":"query","name":"before","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/pre-venda/analytics":{"get":{"summary":"Analytics da pré-venda","tags":["Apps - Pré-venda"],"description":"Unidades pré-vendidas, receita antecipada (subtotal dos itens de pré-venda em pedidos não cancelados na janela), produtos em pré-venda ativos, e taxa de chegada→envio (itens notificados que já foram enviados/entregues). Timeline diária.","parameters":[{"schema":{"type":"string"},"in":"query","name":"desde","required":false},{"schema":{"type":"string"},"in":"query","name":"ate","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/intel/resumo":{"get":{"summary":"Resumo para IA","tags":["Inteligência - IA"],"description":"Top produtos, categorias, ticket médio e diagnósticos (estoque zero, sem foto) dos últimos 30 dias. Consumido pelo copiloto Rê.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tema/atual":{"get":{"summary":"Seções do tema atual","tags":["Configurações - Tema"],"description":"Lê seções do editor de tema com resumo legível por template (home, header, footer, overlays).","parameters":[{"schema":{"type":"string","default":"home","enum":["home","header","footer","overlays"]},"in":"query","name":"template","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tema/sections/{id}":{"patch":{"summary":"Editar seção do tema","tags":["Configurações - Tema"],"description":"Edita campos de uma seção, bloco específico ou reordena posição.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"campos":{"type":"object"},"bloco_id":{"type":"string"},"nova_posicao":{"type":"integer"}}}}}},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Remover seção","tags":["Configurações - Tema"],"description":"Remove seção do tema (busca em todos os templates).","parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/tema/sections":{"post":{"summary":"Adicionar seção","tags":["Configurações - Tema"],"description":"Adiciona nova seção ao template com UUIDs gerados automaticamente.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["tipo"],"properties":{"tipo":{"type":"string"},"template":{"type":"string","default":"home"},"posicao":{"type":"integer"},"config":{"type":"object"},"blocos":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tema/completo":{"put":{"summary":"Sobrescrever tema home","tags":["Configurações - Tema"],"description":"Substitui todas as seções da home (autopilot). Preserva header, footer e overlays.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["sections"],"properties":{"sections":{"type":"array","items":{"type":"object","additionalProperties":true}}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/loja/temas/catalogo":{"get":{"summary":"Catálogo de temas com preço e licença","tags":["Billing - Faturamento"],"description":"Lista os temas ativos com preço, tier e as opções de parcelamento (12x sem juros). Para cada tema, mostra se o tenant já possui a licença (e o número/status/origem dela).","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/loja/temas/{templateId}/comprar":{"post":{"summary":"Comprar tema","tags":["Billing - Faturamento"],"description":"Compra self-service de um tema pago. Preço, cupom e parcelamento são resolvidos/validados no servidor — o body nunca dita valor. Segue a ordem da spec 4.2: resolve preço → valida cupom (resgate atômico) → cupom 100% ativa sem Asaas → grava fatura+licença pendente ANTES do Asaas → cria cobrança → persiste Pix/parcelas. Pix é sempre à vista; 12x sem juros só para cartão/boleto.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["metodo"],"additionalProperties":false,"properties":{"metodo":{"type":"string","enum":["pix","cartao","boleto"]},"parcelas":{"type":"integer","minimum":1,"maximum":12},"cupom":{"type":"string","minLength":1,"maxLength":64}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"templateId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/loja/temas/cupom/validar":{"post":{"summary":"Validar cupom de tema (preview, sem resgatar)","tags":["Billing - Faturamento"],"description":"Confere se o cupom é aplicável ao tema informado e devolve o desconto calculado no servidor. NÃO resgata o cupom (o resgate atômico só acontece na compra). Resposta uniforme para código inexistente/expirado/já usado/fora de escopo — nunca vaza qual dos casos é. Rate limit custom: até 15 tentativas INVÁLIDAS por hora por usuário — validar o mesmo cupom válido repetidas vezes nunca conta para o limite.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["codigo","template_id"],"additionalProperties":false,"properties":{"codigo":{"type":"string","minLength":1,"maxLength":64},"template_id":{"type":"string","format":"uuid"}}}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tenants/{id}/temas/cupons":{"post":{"summary":"Emitir cupom de desconto de tema","tags":["Admin - Backoffice"],"description":"Emite um cupom global de desconto percentual (1-100%) para o tenant informado. max_usos é sempre 1 — não é parametrizável. Código gerado por CSPRNG (≥128 bits, base32 sem caracteres ambíguos), nunca legível/semântico. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["percentual","expira_em"],"additionalProperties":false,"properties":{"percentual":{"type":"integer","minimum":1,"maximum":100},"expira_em":{"type":"string"},"template_id":{"type":"string","format":"uuid"},"tier":{"type":"string","enum":["incluso","essencial","premium"]},"motivo":{"type":"string"}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true}],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/tenants/{id}/temas/{templateId}/revogar":{"post":{"summary":"Revogar licença de tema","tags":["Admin - Backoffice"],"description":"Cancela a licença de um tema do tenant (status -> cancelada). A loja no ar não é derrubada, mas publicar/duplicar o tema passam a ficar bloqueados. Motivo obrigatório. Requer super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["motivo"],"additionalProperties":false,"properties":{"motivo":{"type":"string","minLength":1}}}}},"required":true},"parameters":[{"schema":{"type":"string","format":"uuid"},"in":"path","name":"id","required":true},{"schema":{"type":"string","format":"uuid"},"in":"path","name":"templateId","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/loja/dominio":{"get":{"summary":"Estado do domínio próprio da loja","tags":["Loja - Domínio"],"description":"Retorna subdomínio, domínio próprio, status de verificação, registros DNS exigidos e status do certificado. Requer owner, manager ou super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"subdominio":{"type":"string"},"dominio_proprio":{"type":["null","string"]},"dominio_verificado":{"type":"boolean"},"provisionado":{"type":"boolean"},"ssl_status":{"type":["null","string"]},"apex":{"type":"boolean"},"situacao":{"type":"string"},"diagnostico":{"type":"object","additionalProperties":true,"properties":{"tls_resultado":{"type":["null","string"]},"tls_motivo":{"type":["null","string"]},"tls_checado_em":{"type":["null","string"]},"cert_expira_em":{"type":["null","string"]},"checagens_sem_sucesso":{"type":"number"},"aguardando_desde":{"type":["null","string"]}}},"registros":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"tipo":{"type":"string"},"host":{"type":"string"},"nome_completo":{"type":"string"},"valor":{"type":"string"},"valor_atual":{"type":"string"},"ok":{"type":"boolean"}}}}}}}}}}},"put":{"summary":"Conectar domínio próprio à loja","tags":["Loja - Domínio"],"description":"Valida, registra o domínio no edge (Railway) e retorna os registros DNS que o lojista precisa criar. Trocar o domínio remove o registro anterior. Requer owner, manager ou super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"dominio":{"type":"string"}},"required":["dominio"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"subdominio":{"type":"string"},"dominio_proprio":{"type":["null","string"]},"dominio_verificado":{"type":"boolean"},"provisionado":{"type":"boolean"},"ssl_status":{"type":["null","string"]},"apex":{"type":"boolean"},"situacao":{"type":"string"},"diagnostico":{"type":"object","additionalProperties":true,"properties":{"tls_resultado":{"type":["null","string"]},"tls_motivo":{"type":["null","string"]},"tls_checado_em":{"type":["null","string"]},"cert_expira_em":{"type":["null","string"]},"checagens_sem_sucesso":{"type":"number"},"aguardando_desde":{"type":["null","string"]}}},"registros":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"tipo":{"type":"string"},"host":{"type":"string"},"nome_completo":{"type":"string"},"valor":{"type":"string"},"valor_atual":{"type":"string"},"ok":{"type":"boolean"}}}}}}}}}}},"delete":{"summary":"Desconectar domínio próprio","tags":["Loja - Domínio"],"description":"Remove o domínio do edge e volta a loja a responder apenas no subdomínio da plataforma. Requer owner, manager ou super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/loja/subdominio/disponivel":{"get":{"summary":"O subdomínio está livre?","tags":["Loja - Domínio"],"description":"Valida formato, rótulos reservados e ocupação por outra loja ou site. Requer owner, manager ou super_admin.","parameters":[{"schema":{"type":"string"},"in":"query","name":"valor","required":true}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/loja/subdominio":{"put":{"summary":"Trocar o subdomínio da plataforma","tags":["Loja - Domínio"],"description":"Valida formato, rótulos reservados e ocupação, e grava. O endereço antigo deixa de responder. Requer owner, manager ou super_admin.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"valor":{"type":"string"}},"required":["valor"]}}},"required":true},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/loja/dominio/verificar":{"post":{"summary":"Verificar apontamento do domínio","tags":["Loja - Domínio"],"description":"Consulta o status real no edge (registro a registro + certificado). Quando tudo está propagado, marca o domínio como verificado e a loja passa a responder nele. Cooldown de 30s. Requer owner, manager ou super_admin.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"properties":{"ok":{"type":"boolean"},"dominio_verificado":{"type":"boolean"},"ssl_status":{"type":["null","string"]},"registros":{"type":"array","items":{"type":"object","additionalProperties":true,"properties":{"tipo":{"type":"string"},"host":{"type":"string"},"nome_completo":{"type":"string"},"valor":{"type":"string"},"valor_atual":{"type":"string"},"ok":{"type":"boolean"}}}}}}}}}}}},"/integration":{"get":{"summary":"Listar integrações do tenant","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}":{"get":{"summary":"Detalhe de uma integração","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"patch":{"summary":"Atualizar configuração da integração","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"delete":{"summary":"Desconectar integração (inativar + limpar tokens)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/bling/auth":{"get":{"summary":"Iniciar OAuth Bling V3","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/bling/callback":{"get":{"summary":"Callback OAuth Bling V3","tags":["Integração ERP"],"responses":{"200":{"description":"Default Response"}}}},"/integration/google-ads/auth":{"get":{"summary":"Iniciar OAuth Google Ads","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/google-ads/callback":{"get":{"summary":"Callback OAuth Google Ads","tags":["Integração ERP"],"responses":{"200":{"description":"Default Response"}}}},"/integration/tiny/setup":{"get":{"summary":"Dados de configuração do app Tiny (redirect URI, webhook, estado)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/tiny/credenciais":{"post":{"summary":"Salvar Client ID/Secret do aplicativo Tiny do lojista","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/tiny/auth":{"get":{"summary":"Iniciar OAuth Tiny (API v3)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/tiny/callback":{"get":{"summary":"Callback OAuth Tiny (API v3)","tags":["Integração ERP"],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/preset/canal":{"post":{"summary":"Aplicar o preset de canal de venda (ERP como fonte do catálogo)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/depositos":{"get":{"summary":"Depósitos do ERP e o vínculo atual com os CDs da loja","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}},"put":{"summary":"Vincular cada depósito do ERP a um CD da loja","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/sync/{entity}":{"post":{"summary":"Forçar sync manual de uma entidade","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"entity","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/import":{"post":{"summary":"Importar todos os produtos do ERP (scan full)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/export":{"post":{"summary":"Exportar todos os produtos ativos do tenant para o ERP","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/pedidos/{pedidoId}/erp":{"get":{"summary":"Situação do pedido no ERP","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/pedidos/{pedidoId}/reenviar":{"post":{"summary":"Reenviar um pedido pago ao ERP","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true},{"schema":{"type":"string"},"in":"path","name":"pedidoId","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/reativar":{"post":{"summary":"Testar a conexão com o ERP e reativar a integração","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/report":{"get":{"summary":"Relatório da integração (vínculos reais + erros na janela)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/tiny/webhook/rotacionar":{"post":{"summary":"Gera uma nova URL de notificação (a anterior para de valer)","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/cancelar-rodada":{"post":{"summary":"Descarta os itens ainda na fila da rodada em andamento","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/previa":{"get":{"summary":"Resultado da última prévia de importação","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/{id}/logs":{"get":{"summary":"Logs de sync paginados","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/integration/erp/catalogo":{"get":{"summary":"ERPs de conexão por formulário liberados para esta loja","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/sankhya/conectar":{"post":{"summary":"Testar o token de integração do Sankhya e conectar","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/totvs/conectar":{"post":{"summary":"Testar servidor, usuário e senha do TOTVS Protheus e conectar","tags":["Integração ERP"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/integration/webhook/bling":{"post":{"summary":"Webhook inbound Bling V3 (público)","tags":["Integração ERP"],"responses":{"200":{"description":"Default Response"}}}},"/integration/webhook/tiny/{segredo}":{"post":{"summary":"Webhook inbound Tiny/Olist (público, autenticado pelo segredo da URL)","tags":["Integração ERP"],"parameters":[{"schema":{"type":"string"},"in":"path","name":"segredo","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/integration/feed":{"get":{"summary":"Polling de eventos de integração","tags":["Integração ERP - Feed"],"parameters":[{"schema":{"type":"string"},"in":"query","name":"last_event_id","required":false,"description":"Cursor: ID do último evento processado"},{"schema":{"type":"number","minimum":1,"maximum":100,"default":50},"in":"query","name":"limit","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/api/v1/integration/feed/confirm":{"post":{"summary":"Confirmar eventos do feed como processados","tags":["Integração ERP - Feed"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/notas-fiscais":{"get":{"summary":"Listar notas fiscais do tenant","tags":["Notas Fiscais"],"parameters":[{"schema":{"type":"number","minimum":1,"default":1},"in":"query","name":"page","required":false},{"schema":{"type":"number","minimum":1,"maximum":100,"default":20},"in":"query","name":"limit","required":false},{"schema":{"type":"string","format":"uuid"},"in":"query","name":"pedido_id","required":false},{"schema":{"type":"string","enum":["nfe","nfce"]},"in":"query","name":"tipo","required":false},{"schema":{"type":"string","enum":["emitida","cancelada","denegada"]},"in":"query","name":"status","required":false},{"schema":{"type":"string","enum":["bling","tiny","manual"]},"in":"query","name":"origem","required":false}],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response"}}}},"/notas-fiscais/{id}":{"get":{"summary":"Detalhe de uma nota fiscal","tags":["Notas Fiscais"],"security":[{"bearerAuth":[]}],"parameters":[{"schema":{"type":"string"},"in":"path","name":"id","required":true}],"responses":{"200":{"description":"Default Response"}}}},"/tour-progress":{"get":{"summary":"Progresso do tour guiado do usuário","tags":["Tour"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}},"put":{"summary":"Salvar progresso do tour guiado (autosave)","tags":["Tour"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}}}}},"/public/contato":{"post":{"summary":"Registrar lead do site institucional","tags":["Público - Contato"],"description":"Recebe o formulário de contato/demonstração do site institucional. Sem JWT. Rate limit 5/min por IP.","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["nome","email"],"properties":{"nome":{"type":"string","minLength":2,"maxLength":200},"email":{"type":"string","format":"email","maxLength":200},"telefone":{"type":"string","maxLength":40},"empresa":{"type":"string","maxLength":200},"equipe":{"type":"string","maxLength":60},"mensagem":{"type":"string","maxLength":4000},"interesse":{"type":"string","maxLength":60},"contexto":{"type":"object","additionalProperties":true},"origem":{"type":"string","maxLength":500}}}}},"required":true},"responses":{"201":{"description":"Default Response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}}}}}}}}}},"servers":[{"url":"http://localhost:3000","description":"Local (via Gateway)"},{"url":"https://api.varejohub.com.br","description":"Produção"}],"tags":[{"name":"Catálogo - Produtos","description":"Produtos, variações, imagens, marcas, grades, campos customizados."},{"name":"OMS - Pedidos","description":"Ciclo de vida do pedido (state machine dupla: pagamento × fulfillment), draft orders, devoluções, edit orders."},{"name":"Checkout - Cart (Server-side)","description":"Carrinho server-side (padrão Shopify), link de pagamento, finalização."},{"name":"Logística - Frete","description":"Cotação de frete multi-transportadora, Melhor Envio OAuth, etiquetas, pontos de retirada."},{"name":"Pagamentos","description":"Gateway multi-provider (Pagar.me, MP, Cielo, Rede, Asaas, Dom), Varejo Pay, antifraude."},{"name":"Promoções","description":"Cupons, motor de promoções, fidelidade, gift cards."},{"name":"B2B - Vendas Atacado","description":"Empresas, unidades, listas de preço com volume pricing, catálogos, boleto faturado."},{"name":"Apps","description":"Avaliações, cross-sell, assinaturas, embalagem presente, eventos, registro de App Store."},{"name":"Integrações - ERP","description":"Bling V3 (OAuth2), Tiny V3 (token), Feed v3, webhooks ERP."},{"name":"Busca Inteligente","description":"Busca tsvector PT-BR + trigram + analytics, autocomplete, sinônimos."},{"name":"Clientes","description":"Cadastro PF/PJ unificado, endereços, timeline, lifecycle stage, LTV."},{"name":"LGPD - Consentimento","description":"Ledger append-only de consentimentos, posture de conformidade, banner."},{"name":"Conteúdo - Reels","description":"Reels shoppable (vídeos TikTok-style), atribuição de revenue 24h, import Apify."},{"name":"Conteúdo - Estúdio IA","description":"Geração de criativos via IA, canvas Poppy-style."},{"name":"Configurações - Tema","description":"Editor de temas, sections, customização visual da loja."}]}