Discount codes
Discount codes are yours — you define them for your own end customers. They never change what you pay Linra: your commission, VAT, and settlement are computed exactly as if the order had no discount at all. A code is purely a display/reporting overlay on top of the price Linra computes.
1. Create a code
Section titled “1. Create a code”POST /api/v1/scent/discount-codes{ "code": "SAVE10", "discountType": "Percent", "value": 10, "productScope": "All"}{ "state": "CREATED", "payload": { "id": "5b2e...", "code": "SAVE10", "discountType": "Percent", "value": 10, "isActive": true, "productScope": "All", "usageCount": 0 }}The code string is immutable once created — there is no rename operation. To retire a
typo’d or campaign-ended code, deactivate it and create a new one:
PATCH /api/v1/scent/discount-codes/{id}{ "discountType": "Percent", "value": 10, "isActive": false, "productScope": "All" }Every field on the update call is a full replace (state your complete desired settings each time)
— except code, which the update body has no field for at all.
Guardrails you can set at create/update time
Section titled “Guardrails you can set at create/update time”| Field | Meaning |
|---|---|
validFrom / validTo |
Optional validity window. Both null = open-ended. |
totalUsageCap |
Optional cap on total redemptions across all customers. |
perCustomerCap |
null (no limit) or exactly 1 (at most one redemption per customerRef, ever). No other value is accepted in v1. |
productScope + scopedVariantIds |
All (your whole catalog) or VariantList (an explicit set of variant IDs). |
minOrderValue |
Optional minimum cart total (VAT-inclusive) for the code to apply. |
A code is scoped to you — two partners may both register SAVE10 independently.
2. Validate it against a cart
Section titled “2. Validate it against a cart”Before checkout, check whether a code currently applies — this never consumes a use:
POST /api/v1/scent/cart/discount-code/validate{ "code": "SAVE10" }{ "state": "SUCCESS", "payload": { "valid": true, "reason": null, "originalTotal": 200.00, "discountAmount": 20.00, "discountedTotal": 180.00 }}(Worked from a cart holding 2 units at 100 SAR each — a 10% code computes a 20 SAR discount,
Math.Round-ed to 4 decimal places and never exceeding the cart total.)
If you’ve requested a supported non-SAR display currency via
X-Partner-Currency, the response additionally carries originalTotalDisplay/
discountAmountDisplay/discountedTotalDisplay — the same additive display-currency pattern used
everywhere else in the API, alongside the canonical SAR figures above (never replacing them). The
code’s own configured value (e.g. a fixed-amount discount) is always SAR-denominated regardless of
your display currency — only the computed result shown back here converts for display.
If the code doesn’t apply, valid is false and reason is one of:
| Reason | Meaning |
|---|---|
EMPTY_CART |
Your cart has no lines. |
NOT_FOUND |
No such code for your account. |
INACTIVE |
The code exists but is deactivated. |
NOT_YET_VALID / EXPIRED |
Outside the code’s validity window. |
BELOW_MIN_ORDER_VALUE |
Cart total is below the code’s minOrderValue. |
PRODUCT_SCOPE_MISMATCH |
None of your cart lines are in the code’s VariantList scope. |
CAP_REACHED |
The total-usage cap has been reached (advisory here — see below). |
ALREADY_USED_BY_CUSTOMER |
This customerRef has already redeemed a per-customer-capped code. |
originalTotal/discountAmount/discountedTotal are display figures only — they never change
what you are actually charged.
3. Apply it at order creation
Section titled “3. Apply it at order creation”Pass the SAME code on the order-create call:
POST /api/v1/orders/scent{ "partnerId": "...", "externalReference": "order-42", "discountCode": "SAVE10", "shippingAddress": { "...": "..." }}{ "state": "CREATED", "payload": { "id": "...", "appliedDiscountCode": "SAVE10", "discountAmount": 20.00, "...": "..." }}The code is re-validated at this point (state may have changed since you last validated it — the
usage cap in particular is only advisory at validate time and authoritative here). If it no
longer applies, order creation is rejected with VALIDATION_DISCOUNT_CODE_INVALID,
VALIDATION_DISCOUNT_CODE_EXPIRED, VALIDATION_DISCOUNT_CODE_CAP_REACHED, or
BUSINESS_DISCOUNT_CODE_ALREADY_USED_BY_CUSTOMER — never a silent downgrade to “no discount
applied.” A use is only ever counted when the order itself is actually created: a failed or
cancelled checkout never burns a redemption.
How charging works (the part that never changes)
Section titled “How charging works (the part that never changes)”However a code is defined, it has zero effect on:
- what you pay Linra (wholesale amount, or your commission in commission mode),
- VAT computation and settlement,
- the margin-floor guard.
Those are all computed on the undiscounted price, exactly as if no code were applied. If you want to fund a promotion, it comes out of your own margin — Linra has no stake in it either way.
Managing usage
Section titled “Managing usage”GET /api/v1/scent/discount-codes and GET /api/v1/scent/discount-codes/{id} include a running
usageCount so you can track redemption progress without a separate report. A code that has never
been redeemed (usageCount == 0) can be deleted outright
(DELETE /api/v1/scent/discount-codes/{id}); once it has at least one redemption, delete is
rejected with BUSINESS_DISCOUNT_CODE_IN_USE — deactivate it instead, so the historical order data
referencing it stays meaningful.