Discount Codes
Discount codes are admin-issued promo codes that deduct a flat amount or a percentage from a customer’s order subtotal. They are validated and consumed atomically inside the order transaction — no separate “apply coupon” step is needed.
How it works
Admin creates code Customer validates Customer places orderPOST /admin/discounts → GET /discounts/validate → POST /orders { code: "SAVE20", ?code=SAVE20 { …, discount_code: "SAVE20" } discount_type: "percentage", &subtotal=500 discount_value: 20 } ← { discount_amount: 100, final_total: 400 } ← order.discount_code = "SAVE20" order.discount_amount = 100 order.total_amount = 400- Validate before showing the customer a total. Call
GET /api/v1/discounts/validatewith the cart subtotal whenever the user types a code in the checkout form. - Include the code in the order body. Pass
discount_codeinPOST /api/v1/orders. The server re-validates and atomically increments the code’sused_count— preventing race conditions where two customers claim the last use simultaneously.
Validate a discount code
GET /api/v1/discounts/validate?code=SAVE20&subtotal=500Authorization: Bearer $TOKEN{ "success": true, "data": { "code": "SAVE20", "discount_type": "percentage", "discount_value": 20, "discount_amount": 100, "final_total": 400, "description": "20% off your order — Eid Special" }}| Field | Type | Description |
|---|---|---|
code | string | The normalised (uppercased) discount code. |
discount_type | "percentage" | "flat" | How the discount is computed. |
discount_value | number | The raw value — percentage points or BDT flat amount. |
discount_amount | number | Computed reduction for this subtotal, in BDT. |
final_total | number | Subtotal minus discount (never below 0). |
description | string | null | Admin-set description shown to the customer. |
Validation errors
| HTTP | Message | Cause |
|---|---|---|
400 | "Discount code "X" is not valid or has been deactivated." | Code doesn’t exist or is_active=false. |
400 | "Discount code "X" is not active yet." | Current date is before start_date. |
400 | "Discount code "X" has expired." | Current date is after end_date. |
400 | "Discount code "X" has reached its usage limit." | used_count ≥ usage_limit. |
400 | "Your subtotal (X BDT) is below the minimum purchase (Y BDT)…" | Cart subtotal too low for this code. |
Apply at checkout
Add discount_code to POST /api/v1/orders:
POST /api/v1/ordersAuthorization: Bearer $TOKENContent-Type: application/json
{ "items": [ { "variant_id": 22406, "quantity": 1 } ], "payment_method": "bkash", "discount_code": "SAVE20"}The order response now includes:
{ "success": true, "data": { "id": 101, "order_number": "87654321", "total_amount": 400, "discount_code": "SAVE20", "discount_amount": 100, "status": "INITIATED", "…": "…" }}| Field | Description |
|---|---|
total_amount | Final charged amount after discount. |
discount_code | The code that was applied. null if no code used. |
discount_amount | BDT amount deducted. null if no code used. |
Admin management
Discount codes are created and managed via the admin API
(/admin/discounts). Each code supports:
| Property | Description |
|---|---|
code | Human-readable promo code (auto-uppercased, e.g. SAVE20). |
discount_type | "percentage" or "flat". |
discount_value | Percentage points (0–100) or flat BDT amount. |
min_purchase | Minimum subtotal required to redeem. Defaults to 0. |
max_discount | Cap for percentage discounts (e.g. max 200 BDT off). |
start_date / end_date | Optional validity window. |
usage_limit | Maximum total redemptions. null = unlimited. |
used_count | Auto-incremented; read-only from the client side. |
is_active | Toggle to disable without deleting. |
Related pages
- Checkout flow — full step-by-step integration guide
- Error handling — retry strategy and error patterns
- Error Codes — full error code catalogue