---
id: discounts
title: Handling Discounts
hide_title: true
description: "How to represent discounts in Walley Checkout and handle them during refunds"
---

import Ingress from "../../../src/components/ingress/ingress.react";

<Ingress title="Handling discounts">
  Represent discounts in Walley Checkout so that the amounts still add up when
  you refund the order, in full or in part.
</Ingress>

This guide covers:

- Overview of approaches for different discount models
- Comparison matrix to choose the right model
- Clear end-to-end JSON examples for checkout and refund

## Overview of approaches

Walley supports multiple ways to handle discounts in checkout:

| Approach | Description | When to use |
|----------|-------------|-------------|
| **Explicit discount item** | Represent discounts as a separate negative cart item | Most flexible; recommended for most campaigns |
| **Campaign cases** | Standard patterns like Buy 3 Pay for 2, percent discounts | Use explicit discount items and refund recalculation |
| **Simple discount (adjusted price)** | Discount is baked into the product price | Quick + simple, minimal refund needs |

## Comparison matrix

| Criteria | Explicit discount item | Simple discount |
|----------|----------------------|-----------------|
| **Transparency** | ✅ Customer sees discount item | ⚠️ Only visible in item description |
| **Refund flexibility** | ✅ Fully controllable | ✅ Fully controllable |
| **Partial refunds** | ✅ Supported | ✅ Supported |

## 1. Explicit discount item (recommended)

### Checkout

A discount item is a cart item with a negative `unitPrice` that represents the discount amount. Add the discount item to the cart alongside regular products.

```json
"cart": {
  "items": [
    {
      "id": "item-001",
      "description": "Cool T-shirt",
      "unitPrice": 250,
      "quantity": 1,
      "vat": 25
    },
    {
      "id": "discount-SPRING",
      "description": "Spring campaign discount",
      "unitPrice": -50,
      "quantity": 1,
      "vat": 25
    }
  ]
}
```

### Full refund

```http
POST /manage/orders/{orderId}/refund HTTP/1.1
Content-Type: application/json

{
  "amount": 200,
  "actionReference": "refund-spring-discount",
  "items": [
    { 
      "id": "item-001", 
      "description": "Cool T-shirt", 
      "unitPrice": 250, 
      "quantity": 1, 
      "type": "purchase" 
    },
    { 
      "id": "discount-SPRING", 
      "description": "Spring discount refund", 
      "unitPrice": -50, 
      "quantity": 1, 
      "vat": 25, 
      "type": "discount" 
    }
  ]
}
```

## 2. Partial refund – buy 3, pay for 2 (explicit discount)

This section describes how to model a **Buy 3, Pay for 2** campaign using an explicit discount item, and how to correctly perform a partial refund.

### Original order (Checkout)

**Scenario:**
- 3 products
- Price per product: 100 SEK
- Buy 3, Pay for 2 discount: negative 100 SEK
- Amount paid by customer: 200 SEK

#### Checkout

All products are sent with their full price, and the campaign is represented as a separate discount item.

```json
"cart": {
  "items": [
    {
      "id": "item-001",
      "description": "Product A",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25
    },
    {
      "id": "item-002",
      "description": "Product B",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25
    },
    {
      "id": "item-003",
      "description": "Product C",
      "unitPrice": 100,
      "quantity": 1,
      "vat": 25
    },
    {
      "id": "discount-B3P2",
      "description": "Buy 3, pay for 2 discount",
      "unitPrice": -100,
      "quantity": 1,
      "vat": 25
    }
  ]
}
```

### Partial refund (2 items returned)

**Refund logic:**

The customer returns 2 out of 3 items.

**Refund calculation:**
- Refund products: 2 multiplied by 100 SEK = 200 SEK
- Apply adjusted discount: negative 100 SEK
- **Net refund amount: 100 SEK**

The refund must reflect the net amount paid for the returned items.

#### Refund request

```http
POST /manage/orders/{orderId}/refund HTTP/1.1
Authorization: Bearer <token>
Content-Type: application/json

{
  "amount": 100,
  "actionReference": "partial-refund-buy3pay2",
  "items": [
    {
      "id": "item-001",
      "description": "Product A",
      "unitPrice": 100,
      "quantity": 1,
      "type": "purchase"
    },
    {
      "id": "item-002",
      "description": "Product B",
      "unitPrice": 100,
      "quantity": 1,
      "type": "purchase"
    },
    {
      "id": "discount-B3P2",
      "description": "Buy 3, pay for 2 discount (adjusted)",
      "unitPrice": -100,
      "quantity": 1,
      "vat": 25,
      "type": "discount"
    }
  ]
}
```

**Result:**
- plus 200 SEK refunded for products
- minus 100 SEK discount applied
- Customer receives **100 SEK**

:::info Important notes
- The discount remains negative during refunds
- `type: "discount"` is required for discount items in refunds
- The `amount` must equal the sum of all refund items
- Walley does not recalculate discounts — the merchant must adjust the discount item manually
:::

## 3. Percentage discounts with explicit discount items

### Checkout (10 Percent on 3 Multiplied by 100)

```json
"cart": {
  "items": [
    { "id": "item-001", "description": "Product A", "unitPrice": 100, "quantity": 1, "vat": 25 },
    { "id": "item-002", "description": "Product B", "unitPrice": 100, "quantity": 1, "vat": 25 },
    { "id": "item-003", "description": "Product C", "unitPrice": 100, "quantity": 1, "vat": 25 },
    { "id": "discount-10pct", "description": "10 percent discount", "unitPrice": -30, "quantity": 1, "vat": 25 }
  ]
}
```

### Partial refund (2 items returned, refund amount 180)

```http
POST /manage/orders/{orderId}/refund HTTP/1.1
Content-Type: application/json

{
  "amount": 180,
  "actionReference": "partial-refund-10pct",
  "items": [
    { "id": "item-001", "description": "Product A", "unitPrice": 100, "quantity": 1, "type": "purchase" },
    { "id": "item-002", "description": "Product B", "unitPrice": 100, "quantity": 1, "type": "purchase" },
    { "id": "discount-10pct", "description": "10 percent discount (original)", "unitPrice": -30, "quantity": 1, "vat": 25, "type": "discount" },
    { "id": "discount-10pct-adj", "description": "10 percent discount (remaining)", "unitPrice": 10, "quantity": 1, "vat": 25, "type": "discount" }
  ]
}
```

**Explanation:**
- Original discount refunded: negative 30
- Remaining discount added back: plus 10
- Net discount: negative 20, which results in **amount 180**

## 4. Simple discount (price already adjusted)

Discount is reflected directly in product price — no dedicated discount item.

### Checkout example (10 percent simple)

```json
"cart": {
  "items": [
    {
      "id": "item-001",
      "description": "Product A (10 percent discount applied)",
      "unitPrice": 90,
      "quantity": 1,
      "vat": 25
    }
  ]
}
```

### Simple "Buy 3 Pay 2"

```json
"cart": {
  "items": [
    { "id": "item-001", "description": "Product A (Buy 3 Pay 2)", "unitPrice": 100, "quantity": 1, "vat": 25 },
    { "id": "item-002", "description": "Product B (Buy 3 Pay 2)", "unitPrice": 100, "quantity": 1, "vat": 25 },
    { "id": "item-003", "description": "Product C (Buy 3 Pay 2 – discounted)", "unitPrice": 0, "quantity": 1, "vat": 25 }
  ]
}
```

### Refund with simple discount

```http
POST /manage/orders/{orderId}/refund HTTP/1.1
Content-Type: application/json

{
  "amount": 90,
  "actionReference": "refund-simple-discount",
  "items": [
    { "id": "item-001", "description": "Product A (10 percent discount applied)", "unitPrice": 90, "quantity": 1, "type": "purchase" }
  ]
}
```

## Best practices

- **Use explicit discount items** for campaigns and complex refunds.
- **Use simple discount** when discount logic is internal and refund patterns are trivial.
- Always **align VAT correctly** for both items and discount items.
- **Recalculate discount** for partial refunds and represent in refund request.

## See also

- [Initialize Checkout](/docs/checkout/initcheckout) - Setup checkout sessions with cart items
- [Order Management API](/docs/manage/getting-started/overview) - Capture, refund, cancel orders
- [Inventory Validation Use Case](/docs/checkout/common-use-cases/inventory-validation) - Another callback example
- [Simple Payment Flow](/docs/checkout/common-use-cases/simple-payment-flow) - Complete payment lifecycle
