Implementação de códigos promocionais e descontos

Este guia fornece a referência técnica da API e os esquemas de payload para processar códigos promocionais e descontos na versão 2026-04-08 do Universal Commerce Protocol (UCP).

Antes de criar seus endpoints, consulte a visão geral de códigos promocionais e descontos para conferir os conceitos gerais, invariantes matemáticos e regras de tratamento de erros.

Discovery

Para receber códigos de desconto do Google, você precisa anunciar a compatibilidade com descontos no seu perfil. Na versão 2026-04-08, as plataformas verificam se a capacidade de finalização de compra foi estendida antes de enviar códigos de desconto.

{
  "ucp": {
    "version": "2026-04-08",
    "capabilities": {
      "dev.ucp.shopping.discount": [
        {
          "version": "2026-04-08",
          "extends": ["dev.ucp.shopping.checkout"],
          "spec": "https://ucp.dev/2026-04-08/specification/discount",
          "schema": "https://ucp.dev/2026-04-08/schemas/shopping/discount.json"
        }
      ]
    }
  }
}

Impacto nos itens de linha e totais

Os descontos aplicados são refletidos nos campos principais de finalização de compra usando dois tipos de total distintos. Se um desconto tiver allocations apontando para itens de linha, ele contribuirá para items_discount. Os descontos sem alocações ou com alocações para frete ou taxas contribuem para discount.

Tipo de desconto Tipo de total Onde refletido
Desconto do item de linha items_discount line_items[].totals[type=items_discount]
Desconto no pedido discount totals[type=discount]

Requisito de versão :

Para a versão 2026-04-08, as entradas de desconto em totals[] e line_items[].totals[] precisam usar valores negativos para refletir o efeito de subtração no recibo. Os valores dentro das matrizes discounts.applied e allocations sempre permanecem números inteiros positivos.

Exemplos de API para promoções aplicadas automaticamente

Os exemplos a seguir demonstram descontos aplicados automaticamente. Os payloads de solicitação não contêm uma discounts.codes matriz, mas as respostas incluem "automatic": true e omitem o code campo.

Desconto automático no item

Uma promoção de 10% em todo o site aplicada automaticamente a um item de linha específico.

Exemplo de solicitação:

{
  "line_items": [
    {
      "id": "li_1",
      "item": { "title": "Sneakers", "price": 10000 },
      "quantity": 1
    }
  ]
}

Exemplo de resposta:

{
  "line_items": [
    {
      "id": "li_1",
      "item": { "title": "Sneakers", "price": 10000 },
      "quantity": 1,
      "totals": [
        {"type": "subtotal", "amount": 10000},
        {"type": "items_discount", "amount": -1000},
        {"type": "total", "amount": 9000}
      ]
    }
  ],
  "discounts": {
    "applied": [
      {
        "title": "10% Off Sitewide Sale",
        "amount": 1000,
        "automatic": true,
        "method": "each",
        "allocations": [
          {"path": "$.line_items[0]", "amount": 1000}
        ]
      }
    ]
  },
  "totals": [
    {"type": "subtotal", "display_text": "Subtotal", "amount": 10000},
    {"type": "items_discount", "display_text": "Item Discounts", "amount": -1000},
    {"type": "total", "display_text": "Total", "amount": 9000}
  ]
}

Desconto automático no pedido

Uma regra promocional (por exemplo, "R$ 10 de desconto em pedidos acima de R $50") aplicada ao pedido como um todo sem alocações específicas de itens de linha.

Exemplo de solicitação:

{
  "line_items": [ ... ]
}

Exemplo de resposta:

{
  "line_items": [ ... ],
  "discounts": {
    "applied": [
      {
        "title": "$10 Off Orders Over $50",
        "amount": 1000,
        "automatic": true
      }
    ]
  },
  "totals": [
    {"type": "subtotal", "display_text": "Subtotal", "amount": 6000},
    {"type": "discount", "display_text": "Order Promo", "amount": -1000},
    {"type": "total", "display_text": "Total", "amount": 5000}
  ]
}

Exemplos de API para promoções aplicadas pelo usuário

Os exemplos a seguir demonstram descontos acionados por um usuário que insere um código promocional. Os payloads de solicitação incluem os códigos solicitados, e as respostas os repetem ao alocar os valores aplicados.

Desconto no pedido

Um desconto fixo aplicado ao total do pedido. Nenhuma alocação é necessária. O desconto é aplicado ao pedido como um todo e usa type: "discount".

Exemplo de solicitação:

{
  "line_items": [ ... ],
  "discounts": {
    "codes": ["SAVE10"]
  }
}

Exemplo de resposta:

{
  "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 + 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.

Exemplo de solicitação:

{
  "line_items": [ ... ],
  "discounts": {
    "codes": ["SUMMER20"]
  }
}

Exemplo de resposta:

{
  "line_items": [
    {
      "id": "li_1",
      "item": { "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 um código é inválido, ele é repetido em codes, mas omitido de applied. A rejeição é comunicada usando um warning na matriz messages[].

Exemplo de solicitação:

{
  "line_items": [ ... ],
  "discounts": {
    "codes": ["SAVE10", "EXPIRED50"]
  }
}

Exemplo de resposta:

{
  "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 detalhamentos completos de alocação.

Exemplo de solicitação:

{
  "line_items": [ ... ],
  "discounts": {
    "codes": ["SUMMER20", "EXTRA5"]
  }
}

Exemplo de resposta:

{
  "line_items": [
    {
      "id": "li_1",
      "item": { "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": { "title": "Socks", "price": 4000 },
      "quantity": 1,
      "totals": [
        {"type": "subtotal", "amount": 4000},
        {"type": "items_discount", "amount": -1000},
        {"type": "total", "amount": 3000}
      ]
    }
  ],
  "discounts": {
    "codes": ["SUMMER20", "EXTRA5"],
    "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": "EXTRA5",
        "title": "Extra $5 Off",
        "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}
  ]
}