# Discount Records

To take money off a sale, pick one of the three ways below. [Cart Discounts](/sell/cart/discounts.md) is the cashier's main page for all three. Developers and report readers can go straight to [Where each discount is recorded](#where-recorded).

## Take money off at the till[​](#at-the-till "Direct link to Take money off at the till")

* **One item costs less** — [change its price](#change-price).
* **The whole order costs less** — [take money off the whole order](#add-discount) with **Add Discount**.
* **The customer has a coupon** — [apply a store coupon](#apply-coupon).

Whether they combine on one order depends on [the coupon's rules](/sell/cart/apply-coupon.md#more-than-one). **Add Discount** can't be combined with a coupon marked **Individual use only**.

### Change one item's price[​](#change-price "Direct link to Change one item's price")

1. Tap the price on a line. A keypad opens.
2. Press a percentage key (−5%, −10%, −15%), or type the new price.
3. Press the tick (**✓**) to finish, or **Done** on a phone. The line total changes to the quantity × the new price.

![The price keypad open on a $45.00 line with −10% pressed: the new price $40.50 with $45.00 −10% above it, the three percentage keys, the digit keys, the delete key and the done key](/img/2.x/pos/cart/discounts/en/tablet-light-regular--discounts-1-price-keypad.png)12345

1. **New price** — what the item will cost, and how it was worked out from the price before.
2. **Percentage keys** — each takes its percentage off this line's price. The lit one (here −10%) is in use; press it again to put the old price back. You choose the keys under [**Quick Discounts**](/sell/cart.md#quick-discounts) in **Cart Settings**.
3. **Digits** — type a new price instead.
4. **Delete** — removes the last digit.
5. **✓** — sets the new price.

If you slip:

* **Wrong percentage key** — press another before **✓**; it replaces the first.
* **Want the old price back** — before **✓**, press the lit key again. After **✓**, tap the price again and type the price you want.
* **Closing the keypad** — tapping outside keeps the price you typed. **Escape** on a keyboard keeps the old price.

Other fixes: [If something goes wrong](#if-something-goes-wrong). More: [Take money off one item](/sell/cart/discounts.md#quick-discounts).

### Take money off the whole order[​](#add-discount "Direct link to Take money off the whole order")

1. Press **+** at the top of the cart and choose **Add Discount**.
2. On **Quick discount**, type the amount and choose **$** or **%**.
3. Press **Add Discount**.

![The Add Discount dialog on the Quick discount tab over a cart holding one $45.00 Aim Analog Watch: the Quick discount and Coupon tabs, the amount 10, the dollar and percent switch set to percent, and the Add Discount button](/img/2.x/reference/pos-discounts/en/tablet-light-regular--discounts-2-add-discount-form.png)12345

1. **Quick discount** — an amount or a percentage off this whole order, not one line.
2. **Coupon** — one of your store's coupons instead. See [Apply a coupon](#apply-coupon).
3. **Amount** — tap it and type on the keypad.
4. **$ or %** — a fixed amount off, or a percentage of the order.
5. **Add Discount** — puts the discount on the order.

The discount appears with the totals:

![The cart after a 10% discount on a $45.00 watch: the line total $45.00 struck through with $40.50 under it, the subtotal $45.00, a Discount (10%) row taking off $4.50 with its remove button, and Checkout $40.50](/img/2.x/pos/cart/discounts/en/tablet-light-regular--discounts-5-discount-in-totals.png)1234

1. **Line total** — the price before the discount, struck through, and what the customer pays now.
2. **Subtotal** — the order before the discount.
3. **Discount (10%)** — the discount and how much it takes off. **Discount** alone means a fixed amount. Press **✕** to remove it.
4. **Checkout** — the new total.

To undo it, press **✕** on its row. The line totals go back, and prices changed on lines stay as they were set. Other fixes: [If something goes wrong](#if-something-goes-wrong). More: [Take money off the whole order](/sell/cart/discounts.md#order-level-discounts).

### Apply a coupon[​](#apply-coupon "Direct link to Apply a coupon")

1. Press **+** at the top of the cart and choose **Add Discount** (coupons are in there too).
2. Switch to **Coupon**, press **Select coupon**, and type part of the code to find it.
3. Tap the coupon and press **Apply**.

![The Add Discount dialog on the Coupon tab, with the coupon list open: the Quick discount and Coupon tabs, the Select coupon field, the search box, a coupon with its type and amount, the New coupon button, and the Apply button](/img/2.x/coupons/applying-coupons/en/tablet-light-regular--c-1-coupon-list.png)1234567

1. **Quick discount** — an amount or a percentage off the order, without a coupon. See [Take money off the whole order](#add-discount).
2. **Coupon** — your store's coupons.
3. **Select coupon** — opens the list. Once you pick one, its code shows here.
4. **Search coupons** — type any part of the code or the description.
5. **A coupon** — its code, its description or type, and how much it takes off.
6. **New coupon** (WCPOS Pro) — make a coupon now and apply it to this sale.
7. **Apply** — checks the coupon's rules against this order and puts it on.

The coupon appears in the totals, or the POS says why it can't be used:

![The cart with two coupons applied: the add menu, the subtotal, a row for each coupon with its code, a remove button and the amount it takes off, the item's total with the old amount struck through, and the Checkout button](/img/2.x/coupons/applying-coupons/en/tablet-light-regular--c-3-coupons-applied.png)12345

1. **+** — open **Add Discount** again to add another coupon.
2. **Subtotal** — the order before coupons. The coupon rows sit under it.
3. **A coupon** — its code, the **✕** that removes it, and the amount it takes off.
4. **The next coupon** — each coupon gets its own row, in the order you applied them.
5. **Checkout** — take payment for the order. See [Checkout](/getting-started/make-sale.md).

Picked the wrong one? Press **✕** on its row; the amount it took off goes back on. Refused? See [If the coupon is refused](#coupon-refused). More: [Apply a coupon](/sell/cart/discounts.md#coupon) and [Applying Coupons](/sell/cart/apply-coupon.md).

## If something goes wrong[​](#if-something-goes-wrong "Direct link to If something goes wrong")

* **Wrong price on a line** — tap the price again and type the right one. Before **✓**, pressing the lit percentage key again puts the old price back.
* **Closed the keypad by mistake** — tapping outside keeps the price you typed; **Escape** keeps the old price.
* **Wrong discount on the order** — press **✕** on its row under the totals. The line totals go back; prices changed on lines stay.
* **Wrong coupon** — press **✕** on its row; the amount it took off goes back on.
* **The coupon is refused** — see [If the coupon is refused](#coupon-refused).

### If the coupon is refused[​](#coupon-refused "Direct link to If the coupon is refused")

The dialog stays open and says why in red. Two causes come from the other discounts on the order:

* **… can't be combined with other coupons** or **… is already on the order, and it can't be combined with other coupons** — a coupon marked **Individual use only** must go on alone. Remove the coupon in the way, or keep it and skip the new one.
* **Exclude sale items** — an item whose price was lowered at the till counts as on sale. The coupon skips it, and a coupon for a fixed amount off the order can't be used at all while that item is in the cart. Take that item off, or choose another coupon. Why: [what counts as on sale](#exclude_sale_items-behaviour).

Every other message, with what to do: [When the till refuses a coupon](/sell/cart/apply-coupon.md#refused).

## Where each discount is recorded[​](#where-recorded "Direct link to Where each discount is recorded")

For developers and reports

Nothing below is needed at the till. It is for developers and for anyone reading WCPOS orders in a report, an export or another plugin.

Each way lands in a different place on the order:

* **A changed price** is the line's price: the `_woocommerce_pos_data` meta and the line `subtotal`. It is **not** in `discount_total`, and no coupon rule applies to it.
* **Add Discount** is a coupon line with the code `pos-discount` and `_wcpos_quick_discount` meta. It **is** in `discount_total`. It applies to every product line, sale items included, but can't be combined with a coupon marked **Individual use only**.
* **A store coupon** is a coupon line with the coupon's code. It **is** in `discount_total`, and the coupon's own rules apply.

Here a $45.00 watch had its price typed as $40.00 at the till, then a 10% **Add Discount** went on the order:

![The cart with one Aim Analog Watch: the price lowered at the till from $45.00 to $40.00, the line total $40.00 struck through with $36.00 under it, the subtotal $40.00, a Discount (10%) row taking off $4.00, and Checkout $36.00](/img/2.x/reference/pos-discounts/en/tablet-light-regular--discounts-1-where-recorded.png)12345

1. **Price** — a price changed at the till. Stored per unit in the line's `_woocommerce_pos_data` meta; the line's `subtotal` is this price × quantity. See [How POS price overrides are stored](#how-pos-price-overrides-are-stored).
2. **Line total** — the line's `total`: its `subtotal` less its share of any coupon or **Add Discount**.
3. **Subtotal** — the sum of the line subtotals. It already includes the till price, so the order holds no separate figure for it.
4. **Discount (10%)** — an **Add Discount** line: a coupon line with the code `pos-discount` and `_wcpos_quick_discount` meta. It counts in the order's `discount_total`. See [Add Discount lines](#add-discount-lines).
5. **Checkout** — the order `total`.

In this shot prices include tax: the **US** and **US AL** rows under the totals show the tax inside them. The cart shows amounts with tax, while each line's `subtotal` and `total` and the order's `discount_total` hold them with tax taken out. The order `total` is the grand total, with tax included.

## How POS price overrides are stored[​](#how-pos-price-overrides-are-stored "Direct link to How POS price overrides are stored")

Every product line the POS creates carries the per-unit prices in the `_woocommerce_pos_data` line item meta:

```
{

  "price": "40.00",

  "regular_price": "45.00",

  "tax_status": "taxable"

}
```

* `price` is what the line is sold at, after any change at the till.
* `regular_price` is the product's regular price when it was added. Changing the price at the till never changes it, so a price raised at the till sits above it.
* A [misc product](/sell/cart.md#miscellaneous-products) also carries `virtual`, `downloadable` and `categories`, so coupon rules can check them.

This meta is the authoritative per-unit price. The line's `subtotal` is worked out from `price` × quantity, with tax taken out and rounding applied, and `total` drops below it when a coupon or **Add Discount** applies. For per-unit precision, read `price` and `regular_price` from the meta.

The meta is hidden in WooCommerce's order screen.

Reading the meta from code

**Use a decoder that takes both shapes.** Lines from older apps hold the meta as a JSON string. The 2.0 app writes it as an object, so WordPress stores a serialized array, and values may be numbers rather than strings. A bare `json_decode()` fails on the array.

New POS orders also carry the private `_woocommerce_pos_version` order meta: the version of the WCPOS plugin that saved the order. Receipts still treat the stored line shape as authoritative, because an order taken offline may reach a newer plugin than the app that made it.

## Line totals and the Discount total[​](#subtotal-model-v190 "Direct link to Line totals and the Discount total")

WCPOS records a till price the way WooCommerce records a sale price:

* `line_item.subtotal` = `price` × quantity, where `price` is the till price.
* `line_item.total` = `subtotal` − the line's share of coupons and **Add Discount**.
* `order.discount_total` = coupons and **Add Discount** lines only. A till price is never in it.

A worked example: $45.00 → $40.00 at the till → $36.00

With no tax: a watch with a regular price of $45.00, its price typed as $40.00 at the till, then a 10% **Add Discount**. $40.00 − $4.00 = **$36.00**. The order stores it as:

* `_woocommerce_pos_data.regular_price`: **45.00**
* `_woocommerce_pos_data.price`: **40.00**, the till price
* `line_items[0].subtotal`: **40.00**, 40.00 × 1
* `line_items[0].total`: **36.00**, less the **Add Discount**
* `discount_total`: **4.00**, the **Add Discount** only
* `total`: **36.00**

The $5.00 the till price took off shows only by comparing `regular_price` with `price`. Receipts do that comparison for you; see [Receipt data](#receipt-data-exposure).

Orders from before v1.9.0

Before v1.9.0 the app sent `subtotal` = `regular_price` × quantity. WooCommerce then worked out `discount_total` = `subtotal` − `total`, so a till price counted as a discount. That broke coupon maths: `recalculate_coupons()` works from `subtotal`, so coupons were calculated on the original price. A server-side `woocommerce_order_item_get_subtotal` filter worked around it during `recalculate_coupons()`.

v1.9.0 moved to the sale-price model above and removed the filter. Orders saved before then keep their old figures, which is why a report can show a till price inside `discount_total` on an old order. Receipts allow for it: see [Receipt data](#receipt-data-exposure).

## Add Discount lines[​](#add-discount-lines "Direct link to Add Discount lines")

**Add Discount** takes an amount or a percentage off the whole order. It is a coupon line, not a coupon in your store:

* **Code** — `pos-discount` for the first on an order, then `pos-discount-2`, `pos-discount-3` and so on.
* **Meta** — `_wcpos_quick_discount` on the coupon line: `{ "discount_type": "percent", "amount": "10" }`. `discount_type` is `percent` (up to 100) or `fixed_cart`; `amount` is a positive decimal string.
* **Rules** — it applies to sale items, including prices lowered at the till. It can't be combined with a coupon marked **Individual use only**.
* **Recalculate** — WCPOS stores the coupon details on the line, so **Recalculate** in WooCommerce's order screen keeps the discount.

The virtual coupon exists only while WCPOS saves a POS order: the storefront can't redeem `pos-discount`. If a store coupon already has a code the request uses, the save is refused with **Quick discount code "…" belongs to a store coupon. Use another code.**

The 2.0 app no longer takes money off with a negative fee: it asks for **Add Discount** instead. The plugin still accepts a negative fee line from older apps and other clients.

## Coupon Interaction Behaviour[​](#coupon-interaction-behaviour "Direct link to Coupon Interaction Behaviour")

Applying a store coupon at the till works on the free plugin; creating one at the till needs [WCPOS Pro](/getting-started/pro-license.md). When a coupon is applied to an order that has a till price:

1. The coupon works from the **till price** (`_woocommerce_pos_data.price`), not `regular_price`.
2. Removing the coupon returns the line to its till price.

The app works coupons out on the device, so it can apply one offline, and the plugin works them out again with the same product context when it saves the order.

Where prices include tax and more than one coupon or **Add Discount** reaches a line, the app adds up that line's discounts first and takes the tax out once, as WooCommerce does. The till's line totals then match the saved order to the last decimal.

### `exclude_sale_items` Behaviour[​](#exclude_sale_items-behaviour "Direct link to exclude_sale_items-behaviour")

A line whose `_woocommerce_pos_data.price` is below its `regular_price` counts as on sale, the same as a WooCommerce sale price. A till price at or above `regular_price` doesn't. So a coupon with **Exclude sale items**:

* skips a line whose till price is below its `regular_price`;
* can't be used at all while one is in the cart, if it is a fixed cart coupon. This is WooCommerce's own rule for fixed cart coupons.

To change what counts as on sale, use the `wcpos_item_is_on_sale` filter below.

## Available Filters[​](#available-filters "Direct link to Available Filters")

### `wcpos_item_is_on_sale`[​](#wcpos_item_is_on_sale "Direct link to wcpos_item_is_on_sale")

Override whether a line with POS price data counts as "on sale" when the plugin validates coupons. Before WCPOS 2.0 this filter was named `woocommerce_pos_item_is_on_sale`; that name still works but is deprecated since 2.0 and is removed in 2.2 at the earliest (see [Hook naming](/manage-store/add-ons.md#hook-naming)).

Example and parameters

```
add_filter( 'wcpos_item_is_on_sale', function ( $is_on_sale, $product, $item, $pos_data ) {

    // Let coupons with exclude_sale_items apply to lines lowered at the till.

    return false;

}, 10, 4 );
```

* `$is_on_sale` (`bool`) — whether the line counts as on sale. Default: `price < regular_price`.
* `$product` (`WC_Product`) — the product object.
* `$item` (`WC_Order_Item_Product`) — the order line item.
* `$pos_data` (`array`) — the decoded `_woocommerce_pos_data`.

The filter runs on the server. The app's own on-sale check, used while the cashier is still building the cart, is always `price < regular_price`; the server's answer applies when the order is saved.

## REST API Endpoint[​](#rest-api-endpoint "Direct link to REST API Endpoint")

Coupon endpoints live in the **free plugin**, so the app never gets a 404 when it asks for coupons, even without WCPOS Pro.

The 2.0 app syncs coupons through `GET /wp-json/wcpos/v2/coupons`, which forwards to WooCommerce's `wc/v3/coupons` with the POS read permission. A coupon made at the till (Pro) is saved as an ordinary WooCommerce coupon, and the cashier needs permission to create coupons.

The v1 endpoint, for apps before 2.0

Apps before 2.0 use `/wp-json/wcpos/v1/coupons`. Its controller extends `WC_REST_Coupons_Controller` and adds UUIDs for offline sync, read access for any user with the `access_woocommerce_pos` capability, and a fast ID-only path when `posts_per_page=-1` and `fields=id` (or `fields=id,date_modified_gmt`) are requested.

For who can reach which endpoint, see [Role and Endpoint Access](/developers/role-endpoint-access.md).

## Receipt Data Exposure[​](#receipt-data-exposure "Direct link to Receipt Data Exposure")

Receipt templates get the savings without reading `_woocommerce_pos_data` themselves: each line's savings, one row per coupon or **Add Discount**, and order totals for both.

The receipt fields for discounts and savings

* **Each line** — `regular_price`, `unit_savings` and `line_savings` give what a till price or a sale price saved. `discounts` is the line's `subtotal` − `total`: its share of coupons and **Add Discount**, never a till price. The exception is an order from before v1.9.0, where it may already include the saving: `savings_in_discounts` is then true.
* **`discounts[]`** — one row per coupon line, **Add Discount** included, with `label`, `code`, `discount_type` and `total`. An **Add Discount** row is labelled **Discount (10%)**, or **Discount** for a fixed amount, with `code` `pos-discount` and `discount_type` `percent` or `fixed_cart`.
* **Totals** — `discount_total` (coupons and **Add Discount**, from `WC_Order::get_discount_total()`), `sale_savings_total` (regular-to-selling-price savings, till prices included), and `total_saved` for one figure. `total_saved` removes the overlap on orders from before v1.9.0.
* **`total_saved_complete`** — false when a line lacks the price data for a reliable sum; the savings totals are then `null`.

Each has `_incl` and `_excl` variants. `Receipt_Data_Builder::get_item_meta_pairs()` leaves every underscore-prefixed meta key, `_woocommerce_pos_data` included, out of `lines[].meta`.

See [Displaying regular price and savings](/settings/receipt-templates/receipt-data.md#displaying-regular-price-and-savings) and [Totals](/settings/receipt-templates/receipt-data.md#totals) for template examples.

## Related Documentation[​](#related "Direct link to Related Documentation")

[Cart DiscountsChange a price, add a discount or apply a coupon at the till](/sell/cart/discounts.md)

[Applying CouponsPut a store coupon on a sale, and what its messages mean](/sell/cart/apply-coupon.md)

[Receipt DataEvery field a receipt template can show, savings included](/settings/receipt-templates/receipt-data.md)
