Recipes / Discount audit
OrdersFind every order that carried a discount in a period: who gave it, on what, and how much margin it cost.
Extracted from our discount-orders support tool.
One call returns every order in the date range that carries a non-zero discount. from is required; to defaults to from, both inclusive, Europe/Amsterdam. Money is decimal euros; every _wt field is incl. VAT, its counterpart excl. VAT.
# all discounted orders in June
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30" \
-H "Authorization: Bearer $TOKEN"
{
"from": "2026-06-01",
"to": "2026-06-30",
"shop_id": null,
"only_full": false,
"include_negative": false,
"count": 2,
"total": 2,
"data": [
{ "id": 90412, "order_number": "20260614-0412", "date_purchased": "2026-06-14T11:42:10+02:00",
"status": "complete", "shop_id": 3, "currency": "EUR",
"value_wt": 42.30, "value_ex_wt": 38.81,
"discount_value_wt": 4.70, "discount_value_ex_wt": 4.31,
"customer_name": "Anouk Bakker", "customer_email": "anouk.bakker@example.nl",
"backoffice_url": "https://mybakery.storekeepercloud.com/#order/details/90412" },
{ "id": 90598, "order_number": "20260621-0598", "date_purchased": "2026-06-21T15:03:44+02:00",
"status": "complete", "shop_id": 5, "currency": "EUR",
"value_wt": 0, "value_ex_wt": 0,
"discount_value_wt": 24.95, "discount_value_ex_wt": 20.62,
"customer_name": "S. van Dijk", "customer_email": "",
"backoffice_url": "https://mybakery.storekeepercloud.com/#order/details/90598" }
]
}
value_wt is what the customer actually paid after the discount; discount_value_wt is what was given away. Each row carries a ready-to-click backoffice_url straight to the order, which is what makes this an audit tool: every suspicious number is one click from its source. Pass shop_id to scope to one sales channel.
Two refinements change what counts as "discounted":
only_full=1 keeps only orders where the entire amount was discounted (value_wt is 0). This is the fraud-and-friends filter: 100% discounts are staff comps, test orders, or someone ringing up freebies. The second row above would survive it; the first would not.
include_negative=1 widens the base filter from "discount greater than zero" to "discount not zero", which also catches negative discounts: refund-like corrections. Off by default, so a plain call shows giveaways only.
# every 100%-discounted order in June, one shop
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30&shop_id=3&only_full=1" \
-H "Authorization: Bearer $TOKEN"
# the complete picture including corrections
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30&include_negative=1" \
-H "Authorization: Bearer $TOKEN"
include_negative, do not blindly sum discount_value_wt anymore. Positive and negative rows will partially cancel and understate how much discounting actually happened. Sum the positives and negatives separately and report both.To see what was discounted, fetch the order's line items. Every line has a kind: product, shipping, payment or discount. An order-level discount shows up as its own kind: "discount" line with a negative price; a per-product discount shows up on the product line itself, where ppu_wt × quantity is more than the charged price_wt.
curl -s https://api.storekeeper.me/api/orders/90412/items -H "Authorization: Bearer $TOKEN"
{
"order_id": 90412,
"count": 3,
"truncated": false,
"data": [
{ "id": 512001, "order_id": 90412, "kind": "product", "sku": "BROOD-VOLKOREN",
"name": "Volkorenbrood", "quantity": 4, "ppu": 2.98, "ppu_wt": 3.25,
"price": 11.92, "price_wt": 13.00, "tax_rate_id": 52,
"product_id": 812, "shop_product_id": 5031, "pickup_date": null },
{ "id": 512002, "order_id": 90412, "kind": "product", "sku": "TAART-APPEL",
"name": "Appeltaart groot", "quantity": 2, "ppu_wt": 17.00,
"ppu": 15.60, "price": 28.72, "price_wt": 31.30, "tax_rate_id": 52,
"product_id": 957, "shop_product_id": 5177, "pickup_date": null },
{ "id": 512003, "order_id": 90412, "kind": "discount", "sku": null,
"name": "Kortingscode ZOMER10", "quantity": 1, "ppu": -1.83, "ppu_wt": -2.00,
"price": -1.83, "price_wt": -2.00, "tax_rate_id": 52,
"product_id": null, "shop_product_id": null, "pickup_date": null }
]
}
Both mechanisms are visible here: line 512002 sells two 17.00 taarten for 31.30 instead of 34.00 (a product-line discount of 2.70), and line 512003 subtracts another 2.00 order-wide. Together they explain the header's discount_value_wt of 4.70. The discount line's name usually tells you the mechanism (a coupon code, a manual POS discount).
With the rows in hand, three aggregates answer most audit questions:
Total discount per period and per shop. Sum discount_value_wt grouped by shop_id and compare against the same period last month. A jump at one shop and not the others is a local habit, not a campaign.
Biggest single discounts. Sort by discount_value_wt descending and eyeball the top ten via their backoffice_url. Large one-offs are where mistakes and abuse live.
The 100% list. Run only_full=1 monthly and expect to recognise every row (staff meals, samples, replacements). Any row you cannot explain is exactly what this recipe exists for.
# the monthly audit set, in three calls
per_shop_total = sum(discount_value_wt) group by shop_id
top_10 = sort by discount_value_wt desc, take 10
full_discounts = ?only_full=1 rows, reviewed by a human
Recepten / Kortingsaudit
OrdersVind elke order met korting in een periode: wie gaf hem, waarop, en hoeveel marge het kostte.
Overgenomen uit onze kortingsorders-supporttool.
Eén aanroep geeft elke order in het datumbereik met een korting die niet nul is. from is verplicht; to valt terug op from, beide inclusief, Europe/Amsterdam. Bedragen zijn decimale euro's; elk _wt-veld is incl. btw, de tegenhanger excl. btw.
# alle orders met korting in juni
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30" \
-H "Authorization: Bearer $TOKEN"
value_wt is wat de klant na de korting echt betaalde; discount_value_wt is wat is weggegeven. Elke rij draagt een klikklare backoffice_url rechtstreeks naar de order, en dat maakt dit een auditgereedschap: elk verdacht getal staat één klik van zijn bron. Geef shop_id mee om tot één verkoopkanaal te beperken.
Twee verfijningen veranderen wat als "met korting" telt:
only_full=1 houdt alleen orders over waar het hele bedrag is weggekort (value_wt is 0). Dit is het filter voor fraude en vriendjes: 100%-kortingen zijn personeelsmaaltijden, testorders, of iemand die gratis meegeeft.
include_negative=1 verbreedt het basisfilter van "korting groter dan nul" naar "korting niet nul", waardoor ook negatieve kortingen meekomen: correcties die op een terugbetaling lijken. Standaard uit, dus een kale aanroep toont alleen weggegeven korting.
# elke 100%-weggekorte order in juni, één winkel
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30&shop_id=3&only_full=1" \
-H "Authorization: Bearer $TOKEN"
# het complete beeld inclusief correcties
curl -s "https://api.storekeeper.me/api/discount-orders?from=2026-06-01&to=2026-06-30&include_negative=1" \
-H "Authorization: Bearer $TOKEN"
include_negative aanzet, mag je discount_value_wt niet meer blind optellen. Positieve en negatieve rijen strepen elkaar deels weg en je onderschat hoeveel korting er echt is gegeven. Tel de positieve en negatieve rijen apart op en rapporteer beide.Om te zien wat er is weggekort, haal je de orderregels op. Elke regel heeft een kind: product, shipping, payment of discount. Een korting op orderniveau verschijnt als een eigen regel met kind: "discount" en een negatieve prijs; een korting per product zit op de productregel zelf, waar ppu_wt × quantity meer is dan het gerekende price_wt.
curl -s https://api.storekeeper.me/api/orders/90412/items -H "Authorization: Bearer $TOKEN"
Beide mechanismen zijn zo zichtbaar: een productregel die twee taarten van 17,00 voor 31,30 in plaats van 34,00 verkoopt, plus een aparte kortingsregel die orderbreed nog 2,00 aftrekt. Samen verklaren ze de discount_value_wt van de orderkop. De name van de kortingsregel vertelt je meestal het mechanisme (een kortingscode, een handmatige kassakorting).
Met de rijen binnen beantwoorden drie aggregaties de meeste auditvragen:
Totale korting per periode en per winkel. Som discount_value_wt gegroepeerd op shop_id en vergelijk met dezelfde periode vorige maand. Een sprong bij één winkel en niet bij de rest is een lokale gewoonte, geen campagne.
Grootste losse kortingen. Sorteer aflopend op discount_value_wt en bekijk de top tien via hun backoffice_url. In grote uitschieters wonen de fouten en het misbruik.
De 100%-lijst. Draai maandelijks only_full=1 en verwacht dat je elke rij herkent (personeelsmaaltijden, monsters, vervangingen). Elke rij die je niet kunt verklaren is precies waarvoor dit recept bestaat.
# de maandelijkse auditset, in drie stappen
per_shop_total = som(discount_value_wt) groepeer op shop_id
top_10 = sorteer op discount_value_wt aflopend, neem 10
full_discounts = rijen van ?only_full=1, door een mens bekeken