Preços

Todo produto tem uma tabela de preços por trás, mesmo quando é só uma linha. Dois modelos cobrem os dois jeitos de vender na plataforma: preço único (default), para quem vende no varejo, e preço progressivo por quantidade (wholesale, até 5 faixas), para quem também atende atacado e quer que o preço caia conforme a quantidade sobe.


Conceitos

price_type vive no produto e dita o comportamento da tabela:

price_typeFaixas permitidasmin_quantity
defaultExatamente 1Sempre 1
wholesale1 a 5 progressivas1, depois valores crescentes

O teto de 5 faixas vale para qualquer produto: a sexta faixa é recusada com 400.

Faixa é cada linha da tabela: par (min_quantity, price). A faixa que vale numa venda é a de maior min_quantity cujo valor é quantidade comprada.

A chave de cada faixa é o min_quantity. É por isso que PUT e DELETE recebem ele no path.

Quer voltar de wholesale para default? Só depois de deixar uma faixa só. Como o default é, por definição, uma tabela de uma linha, a plataforma não tem como adivinhar qual das suas faixas de atacado deve sobreviver: a decisão fica com você. Apague as faixas extras primeiro e aí a troca é liberada.

GET /products/{id}/prices devolve sempre um array de faixas: o que muda é o conteúdo conforme o price_type.

Padrão (default): exatamente 1 faixa.

[
  {
    "min_quantity": 1,        // sempre 1 no default
    "value": 89.9,            // preço unitário único
    "discount_percent": null  // não se aplica
  }
]

Atacado (wholesale): 1 a 5 faixas progressivas.

[
  {
    "min_quantity": 1,        // faixa base: preço da UMA unidade
    "value": 50.0,
    "discount_percent": null  // no atacado automático a base fica 0; o % vai nas faixas seguintes
  },
  {
    "min_quantity": 10,       // faixa de atacado: a partir de 10 un
    "value": 45.0,            //   preço unitário menor
    "discount_percent": null
  }
]

No produto (GET /api/products e GET /api/products/{id}), o wholesale não devolve um price único: a resposta traz min_price e max_price (o menor e o maior valor entre estas faixas).


Escala do preço (casas decimais)

O campo price das faixas (POST /api/products/{id}/prices e PUT /api/products/{id}/prices/{min_quantity}) aceita no máximo price_scale casas decimais:

advanced_pricing do produtoprice_scaleCasas aceitas no price
false (padrão)22
true33

Enviar 3 casas decimais em um SKU sem advanced_pricing retorna 422. O price_scale vem no objeto do produto (somente leitura): consulte-o antes de formatar e enviar o preço.

A precisão de 3 casas vale só para o preço unitário. O subtotal da linha e tudo que vem depois dele (totais do pedido, frete, comissão, split e pagamento) são sempre calculados com 2 casas, arredondados para cima. O motivo é prático: o gateway de pagamento não representa meio centavo.

Exemplo: unitário 0.375 (3 casas, produto com advanced_pricing) × 3 unidades = 1.125, cobrado como 1.13.


Preço padrão (default)

Produto vendido por valor unitário. Uma única faixa, sempre com min_quantity = 1.

Criar

POST/api/products/{id}/prices

{
  "min_quantity": 1,
  "price": 89.90
}

Atualizar

PUT/api/products/{id}/prices/1

{
  "price": 79.90
}

Preço de atacado (wholesale)

Tabela progressiva por volume, até 5 faixas. Cada faixa tem o preço unitário vendido a partir daquela quantidade.

Recomendado: precifique por desconto (%), não por valor fixo. Ligando o auto_wholesale_pricing, você informa só o discount_percent de cada faixa e deixa o preço ser derivado do preço base. A gestão fica automática: você reajusta o preço base num lugar só e todas as faixas se recalculam sozinhas, sem reabrir faixa por faixa e sem risco de a tabela ficar inconsistente. Os dois modos estão documentados abaixo, mas comece pelo Atacado automático.

Exemplo de tabela montada:

Faixamin_quantityprice (unitário)Quando vale
11R$ 50,001 a 9 unidades
210R$ 45,0010 a 49 unidades
350R$ 40,0050 unidades ou mais

A faixa base (min_quantity = 1) é sempre o preço unitário. As faixas de atacado são as de min_quantity ≥ 2.

Adicionar uma faixa (modo manual)

POST/api/products/{id}/prices

No modo manual você informa o price de cada faixa diretamente e fica responsável por reajustar faixa a faixa quando o preço mudar. (Para uma gestão mais simples, prefira o Atacado automático, a abordagem recomendada, em que você precifica por desconto.)

Faixa base (min_quantity = 1):

{
  "min_quantity": 1,
  "price": 50.00
}

Faixa de atacado:

{
  "min_quantity": 10,
  "price": 45.00
}

Reajustar uma faixa existente

PUT/api/products/{id}/prices/10

O corpo aceita o price e/ou o discount_percent. O merge parcial vale só para o discount_percent. O price não: se você não mandar, ele é zerado (no modo manual e na faixa base). Sempre reenvie o price no PUT.

{
  "price": 42.50
}

Remover uma faixa

DELETE/api/products/{id}/prices/10

A faixa base (min_quantity = 1) é protegida: tentar apagá-la devolve 400 com "Preço mínimo não pode ser removido". Todo produto sempre tem preço unitário.

O min_quantity de uma faixa também não muda no PUT — ele é a chave. Para mover uma faixa de 10 para 12, apague a de 10 e crie a de 12.


O que pode dar errado

ErroQuando aconteceComo tratar
400 "Preço máximo atingido."Você já tem 5 faixas nesse produto.Remova uma faixa antes de criar outra.
400 "Preço mínimo não pode ser removido."DELETE na faixa min_quantity = 1.A faixa base não sai; para trocar o valor, use o PUT.
409 DUPLICATEDPOST com um min_quantity que já existe.Use o PUT daquela faixa em vez do POST.
422 "Quantidade de preço inválida."Faixa com min_quantity >= 2 num produto default.Troque o price_type do produto para wholesale primeiro.
422 "Defina o preço unitário base antes de criar faixas de atacado automáticas."Atacado automático sem a faixa base cadastrada.Crie a faixa min_quantity = 1 antes.
422 desconto não progressivoNo atacado automático, a faixa maior tem desconto menor ou igual ao da faixa anterior.Garanta descontos crescentes conforme a quantidade sobe.
422 casas decimaisprice com mais casas que o price_scale do SKU.Ligue o advanced_pricing ou arredonde para 2 casas.
422 SUBSTORE_CATALOG_READ_ONLYA loja opera em modo espelho.Preço é gerenciado pela matriz.

Atacado automático

É a abordagem recomendada para o atacado: o preço passa a ser gerido num ponto só, o que mantém a tabela sempre coerente.

O produto tem um interruptor auto_wholesale_pricing (definido no próprio produto, junto do price_type). Quando ligado, você para de informar o price das faixas de atacado e passa a informar só o desconto (discount_percent). O preço de cada faixa é derivado do preço unitário base menos o desconto.

O discount_percent é sempre relativo ao preço base. O que fica salvo na faixa é o desconto, não um valor fixo: por isso, se você mudar o preço base, todas as faixas de atacado são recalculadas aplicando de novo o desconto de cada uma. Você ajusta o preço num lugar só.

Exemplo: preço base R$ 50,00, faixa de 50 un com discount_percent: 20 → preço da faixa = R$ 40,00. Se depois o base virar R$ 60,00, a mesma faixa passa sozinha para R$ 48,00.

Regras desse modo:

  • O preço base (min_quantity = 1) precisa existir antes de criar faixas de atacado: é dele que sai o cálculo. Sem ele, a API responde 422.
  • O discount_percent vai de 0 a menos de 100.
  • Os descontos precisam ser progressivos: faixa de quantidade maior exige desconto maior que a anterior (o preço sempre cai conforme a quantidade sobe). Caso contrário, 422.

Faixa de atacado por desconto (em vez de price):

{
  "min_quantity": 50,
  "discount_percent": 20
}

Comparando os dois modos para a mesma faixa: no manual você manda "price": 40.00; no automático você manda "discount_percent": 20 e a API calcula o preço a partir do base. No modo manual o discount_percent é ignorado.


Listar a tabela

GET/api/products/{id}/prices

{
  "success": true,
  "message_code": "SUCCESS",
  "data": [
    {
      "value": 50.00,
      "min_quantity": 1,
      "discount_percent": null
    },
    {
      "value": 45.00,
      "min_quantity": 10,
      "discount_percent": null
    }
  ]
}

Cada faixa traz o valor (value), o min_quantity e o discount_percent (preenchido no atacado automático). A lista já vem ordenada por min_quantity ascendente, pronta pra renderizar na tela do comprador.