Extensão de desconto¶
Visão geral¶
A extensão de desconto permite que as empresas indiquem que apoiam códigos de desconto nas sessões de carrinho e checkout, e especifica como os códigos de desconto são compartilhados entre a plataforma e o negócio.
Principais recursos:
- Envie um ou mais códigos de desconto
- Receba descontos aplicados com títulos e valores legíveis por humanos
- Códigos rejeitados comunicados via
messages[]com códigos de erro detalhados - Descontos automáticos coexistem com descontos baseados em código
Dependências:
- Capacidade de carrinho ou capacidade de checkout
Descoberta¶
As empresas anunciam suporte a descontos em seus perfis. A capacidade pode estender carrinho, checkout ou ambos:
{
"ucp": {
"version": "2026-07-28",
"capabilities": {
"br.dev.bcp.shopping.discount": [
{
"version": "2026-07-28",
"extends": ["br.dev.bcp.shopping.cart", "br.dev.bcp.shopping.checkout"],
"spec": "https://bcp.dev.br/draft/specification/discount",
"schema": "https://bcp.dev.br/draft/schemas/shopping/discount.json"
}
]
}
}
}
As empresas PODEM anunciar suporte a desconto apenas para carrinho, apenas para checkout ou para ambos. As plataformas DEVEM verificar quais recursos são estendidos antes de enviar códigos de desconto.
Esquema¶
Quando esse recurso está ativo, o carrinho e/ou checkout são estendidos com um
objeto discounts.
Objeto de descontos¶
Entrada de códigos de desconto e saída de descontos aplicados.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| codes | Array[string] | Não | Códigos de desconto a aplicar. Não diferencia maiúsculas de minúsculas. Substitui os códigos enviados anteriormente. Envie um array vazio para limpar. |
| applied | Array[object] | Não | Descontos aplicados com sucesso (baseados em código e automáticos). |
Desconto Aplicado¶
Um desconto que foi aplicado com sucesso.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| code | string | Não | O código de desconto. Omitido para descontos automáticos. |
| title | string | Sim | Nome do desconto legível por humanos (ex.: 'Summer Sale 20% Off'). |
| amount | integer | Sim | Valor total do desconto em unidades menores ISO 4217. |
| automatic | boolean | Não | Verdadeiro se aplicado automaticamente por regras do lojista (sem necessidade de código). |
| method | string | Não | Método de alocação. 'each' = aplicado independentemente por item. 'across' = dividido proporcionalmente por valor. Enum: each, across |
| priority | integer | Não | Ordem de empilhamento para o cálculo do desconto. Números menores são aplicados primeiro (1 = primeiro). |
| provisional | boolean | Não | Verdadeiro se este desconto requer verificação adicional. |
| eligibility | string | Não | A claim de elegibilidade aceita pela Empresa para este desconto. Corresponde a um valor de context.eligibility. Omitida para descontos baseados em código e automáticos não relacionados a elegibilidade. |
| allocations | Array[object] | Não | Detalhamento de onde este desconto foi alocado. A soma dos valores de alocação é igual ao valor total. |
Alocação¶
Detalhamento de como um valor de desconto foi alocado a um alvo específico.
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
| path | string | Sim | JSONPath para o alvo da alocação (ex.: '$.line_items[0]', '$.totals.shipping'). |
| amount | integer | Sim | Valor alocado a este alvo em unidades menores ISO 4217. |
Detalhes de alocação¶
A matriz applied explica como os descontos foram calculados e distribuídos.
O applied[].amount descreve a magnitude do desconto aplicado (sempre
positivo); o valor da entrada totals[] correspondente representa seu efeito, com
sinal, sobre o total (negativo para descontos).
Método de alocação¶
O campo method indica como foi calculado o desconto:
| Método | Significado | Exemplo |
|---|---|---|
each |
Aplicado de forma independente por item elegível | “10% de desconto em cada item” → 10% × preço do item |
across |
Dividir proporcionalmente por valor | "Desconto de $ 10 no pedido" → item de $ 6 a $ 60, item de $ 4 a $ 40 |
Ordem de empilhamento¶
Quando são aplicados descontos múltiplos, priority indica a ordem de cálculo.
Números mais baixos são aplicados primeiro:
Cart: $100
Discount A (priority: 1): 20% off → $100 × 0.8 = $80
Discount B (priority: 2): $10 off → $80 - $10 = $70
A ordem é importante porque os descontos percentuais são compostos de forma diferente dependendo quando eles são aplicados.
Matriz de Alocações¶
A matriz allocations divide onde cada dólar de desconto foi parar, usando
JSONPath para identificar alvos:
| Padrão de caminho | Alvo |
|---|---|
$.line_items[0] |
Item de primeira linha |
$.line_items[1] |
Segunda linha |
$.totals.shipping |
Custos de envio |
Isso permite que as plataformas expliquem exatamente quanto cada desconto contribuiu para cada item de linha, mesmo quando vários descontos se acumulam.
Invariante: Soma de allocations[].amount é igual a applied_discount.amount.
Operações¶
Os códigos de desconto são enviados por meio das operações padrão de criação/atualização de carrinho ou checkout. A mesma semântica se aplica a ambos os recursos.
Solicitar comportamento:
- Semântica de substituição: o envio de
discounts.codessubstitui quaisquer códigos enviados anteriormente - Limpar códigos: Envie o array vazio
"codes": []para remover todos os códigos de desconto - Não diferencia maiúsculas de minúsculas: os códigos são correspondidos sem distinção entre maiúsculas e minúsculas por empresa
Comportamento de resposta:
discounts.appliedcontém todos os descontos ativos (baseados em código + automáticos)- Códigos rejeitados comunicados via
messages[](veja abaixo) - Valores de desconto refletidos em
totals[]eline_items[].totals[]
Continuidade do carrinho até o checkout: quando um carrinho é convertido em checkout por
meio do campo cart_id da capacidade do carrinho, as empresas DEVEM transferir quaisquer
códigos de desconto que foram aplicados ao carrinho. Códigos que não são mais válidos no
momento do checkout (por exemplo, expirado, inelegível) DEVEM ser comunicados via
messages[] usando códigos de rejeição padrão.
Códigos rejeitados¶
Quando um código de desconto enviado não pode ser aplicado, as empresas comunicam isso
através da matriz messages[]:
[
{
"type": "warning",
"code": "discount_code_expired",
"path": "$.discounts.codes[0]",
"content": "Code 'SUMMER20' expired on December 1st"
}
]
Orientação de implementação: Operações que afetam os totais dos pedidos ou a expectativa do usuário em relação ao total DEVEM usar
type: "warning"para garantir que eles sejam apresentados ao usuário, em vez de manipulados silenciosamente pelas plataformas. Descontos rejeitados são um excelente exemplo: o usuário espera um desconto, mas não o recebe, por isso deve ser informado.
Códigos de erro para descontos rejeitados:
| Código | Descrição |
|---|---|
discount_code_expired |
O código expirou |
discount_code_invalid |
Código não encontrado ou malformado |
discount_code_already_applied |
O código já está aplicado |
discount_code_combination_disallowed |
Não acumulável com outro desconto ativo |
discount_code_user_not_logged_in |
O código requer usuário autenticado |
discount_code_user_ineligible |
O usuário não atende aos critérios de elegibilidade |
Descontos Automáticos¶
As empresas podem aplicar descontos automaticamente com base no conteúdo do carrinho, segmento de cliente ou regras promocionais:
- Aparece em
discounts.appliedcomautomatic: truee sem campocode - Aplicado sem ação de plataforma
- Não pode ser removido pela plataforma
- Apresentado para transparência (a plataforma pode explicar ao usuário por que o desconto foi aplicado)
Reivindicações de elegibilidade¶
As reivindicações de elegibilidade são reivindicações do comprador sobre benefícios elegíveis (consulte
Contexto), como associação de fidelidade, vantagens de
instrumento de pagamento e similares. Quando a extensão de desconto está ativa, as
empresas que optarem por aceitar reivindicações de elegibilidade DEVEM revelar seu
efeito nos preços como descontos provisórios na matriz applied. Plataformas DEVEM
exibir descontos provisórios ao comprador.
Comportamento de desconto¶
As plataformas enviam reclamações do comprador via context.eligibility nas
solicitações de carrinho ou checkout (consulte Contexto). Quando
uma empresa reconhece uma reivindicação que afeta o preço, ela DEVE apresentar um
desconto provisório correspondente na matriz discounts.applied. Isto dá à plataforma
atribuição estruturada para exibir ao comprador.
Os descontos acionados por elegibilidade usam os seguintes campos:
| Campo | Valor | Finalidade |
|---|---|---|
automatic |
true |
Nenhum código necessário |
provisional |
true |
Requer verificação na conclusão |
eligibility |
"com.example.store_card" |
A reivindicação aceita |
code |
(omitido) | Não baseado em código |
Os campos padrão priority, method e allocations aplicam-se ao empilhamento com
outros descontos.
Verificação no checkout¶
Os descontos de reivindicações aceitas, mas não verificadas, são provisional: true.
Os descontos provisórios permanecem até que a reclamação seja verificada, rescindida ou
substituída durante a sessão. Na conclusão do checkout, todas as reivindicações
provisórias restantes DEVEM ser resolvidas (consulte
Verificação de elegibilidade na conclusão).
Exemplo: Desconto Provisório com Atribuição¶
Com base no exemplo do cartão da loja de Verificação de elegibilidade na conclusão, a extensão de desconto fornece atribuição estruturada. A plataforma reivindica um benefício do cartão da loja; a empresa apresenta o desconto provisório com detalhes completos de empilhamento e alocação:
{
"ucp": { ... },
"id": "...",
"currency": "...",
"line_items": [ ... ],
"discounts": {
"applied": [
{
"title": "Store Card 5% Off",
"amount": 250,
"automatic": true,
"provisional": true,
"eligibility": "com.example.store_card",
"priority": 1,
"method": "each",
"allocations": [
{"path": "$.line_items[0]", "amount": 250}
]
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 5000},
{"type": "items_discount", "display_text": "Discounts", "amount": -250},
{"type": "total", "display_text": "Total", "amount": 4750}
]
}
A plataforma agora pode renderizar: "Cartão da loja com 5% de desconto: -$2,50 (verificado em compra)" com total confiança na atribuição, valor e alocação.
Impacto em itens de linha e totais¶
Os descontos aplicados são refletidos nos campos principais do carrinho ou checkout usando dois tipos totais distintos:
| Tipo total | Quando usar |
|---|---|
items_discount |
Descontos atribuídos a itens de linha ($.line_items[*]) |
discount |
Descontos no nível do pedido (frete, taxas, valor fixo do pedido) |
Determinando o tipo: Se um desconto tiver allocations apontando para itens de
linha, contribui para items_discount. Descontos sem alocações, ou com alocações
para frete/taxas, contribuem para discount.
| Tipo de desconto | Onde refletido |
|---|---|
| Desconto em itens de linha | line_items[].totals[type=items_discount] |
| Desconto no nível do pedido | totals[type=discount] |
Invariante: totals[type=items_discount].amount é igual
sum(line_items[].totals[type=items_discount].amount).
A matriz discounts.applied mostra o que foi aplicado. O totals[] e
line_items[].totals[] mostra onde e quanto.
Convenção de valor: Os valores de desconto em discounts.applied são inteiros
positivos (o valor do desconto). As entradas de desconto em totals[] são negativas
(o efeito no recibo) — o sinal é aplicado pelo esquema.
Exemplos¶
Carrinho com códigos de desconto¶
Códigos de desconto aplicados durante a exploração do carrinho. A resposta do carrinho inclui valores estimados de desconto, dando ao comprador visibilidade sobre a economia antes de prosseguir para o checkout.
{
"ucp": { ... },
"id": "cart_abc123",
"currency": "BRL",
"line_items": [
{
"id": "li_1",
"item": {
"id": "prod_1",
"title": "T-Shirt",
"price": 2000
},
"quantity": 2,
"totals": [
{"type": "subtotal", "amount": 4000},
{"type": "items_discount", "amount": -800},
{"type": "total", "amount": 3200}
]
}
],
"discounts": {
"codes": ["SUMMER20"],
"applied": [
{
"code": "SUMMER20",
"title": "Summer Sale 20% Off",
"amount": 800,
"method": "each",
"allocations": [
{"path": "$.line_items[0]", "amount": 800}
]
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 4000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -800},
{"type": "total", "display_text": "Estimated Total", "amount": 3200}
]
}
Desconto no nível do pedido¶
Um desconto fixo aplicado ao total do pedido. Sem alocações – o desconto se aplica
ao pedido como um todo e utiliza type: "discount" nos totais.
{
"ucp": { ... },
"id": "...",
"currency": "...",
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10"],
"applied": [
{
"code": "SAVE10",
"title": "$10 Off Your Order",
"amount": 1000
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 5000},
{"type": "discount", "display_text": "Order Discount", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 4000}
]
}
Descontos mistos (item + nível do pedido)¶
Este exemplo mostra os dois tipos de desconto: um desconto por item (20% de desconto) alocado para itens de linha e um desconto de frete automático no nível do pedido.
{
"ucp": { ... },
"id": "...",
"currency": "...",
"line_items": [
{
"id": "li_1",
"item": {
"id": "prod_1",
"title": "T-Shirt",
"price": 2000
},
"quantity": 2,
"totals": [
{"type": "subtotal", "amount": 4000},
{"type": "items_discount", "amount": -800},
{"type": "total", "amount": 3200}
]
}
],
"discounts": {
"codes": ["SUMMER20"],
"applied": [
{
"code": "SUMMER20",
"title": "Summer Sale 20% Off",
"amount": 800,
"allocations": [
{"path": "$.line_items[0]", "amount": 800}
]
},
{
"title": "Free shipping on orders over $30",
"amount": 599,
"automatic": true
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 4000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -800},
{"type": "discount", "display_text": "Order Discounts", "amount": -599},
{"type": "fulfillment", "display_text": "Shipping", "amount": 0},
{"type": "total", "display_text": "Total", "amount": 2601}
]
}
Código de desconto rejeitado¶
Quando não for possível aplicar um código de desconto, a rejeição é comunicada através da
matriz messages[]. O código ainda aparece em discounts.codes (ecoado de volta)
mas não em discounts.applied.
{
"ucp": { ... },
"id": "...",
"currency": "...",
"line_items": [ ... ],
"discounts": {
"codes": ["SAVE10", "EXPIRED50"],
"applied": [
{
"code": "SAVE10",
"title": "$10 Off Your Order",
"amount": 1000
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 5000},
{"type": "discount", "display_text": "Order Discount", "amount": -1000},
{"type": "total", "display_text": "Total", "amount": 4000}
],
"messages": [
{
"type": "warning",
"code": "discount_code_expired",
"path": "$.discounts.codes[1]",
"content": "Code 'EXPIRED50' expired on December 1st"
}
]
}
Descontos acumulados com alocações¶
Vários descontos aplicados com detalhamento total da alocação:
{
"ucp": { ... },
"id": "...",
"currency": "...",
"line_items": [
{
"id": "li_1",
"item": {
"id": "prod_1",
"title": "T-Shirt",
"price": 6000
},
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 6000},
{"type": "items_discount", "amount": -1500},
{"type": "total", "amount": 4500}
]
},
{
"id": "li_2",
"item": {
"id": "prod_2",
"title": "Socks",
"price": 4000
},
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 4000},
{"type": "items_discount", "amount": -1000},
{"type": "total", "amount": 3000}
]
}
],
"discounts": {
"codes": ["SUMMER20", "LOYALTY5"],
"applied": [
{
"code": "SUMMER20",
"title": "Summer Sale 20% Off",
"amount": 2000,
"method": "each",
"priority": 1,
"allocations": [
{"path": "$.line_items[0]", "amount": 1200},
{"path": "$.line_items[1]", "amount": 800}
]
},
{
"code": "LOYALTY5",
"title": "$5 Loyalty Reward",
"amount": 500,
"method": "across",
"priority": 2,
"allocations": [
{"path": "$.line_items[0]", "amount": 300},
{"path": "$.line_items[1]", "amount": 200}
]
}
]
},
"totals": [
{"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
{"type": "items_discount", "display_text": "Item Discounts", "amount": -2500},
{"type": "total", "display_text": "Total", "amount": 7500}
]
}
Com esses dados, um agente pode explicar:
"Sua camiseta (US$ 60) ganhou US$ 12 de desconto na promoção de verão de 20%, mais US$ 3 da sua recompensa de fidelidade (dividida proporcionalmente). Economia total neste item: US$ 15.