Skip to main content
Authenticated API

This endpoint requires a valid JWT Bearer token. Accessible via the API gateway at /v1/commerce/*.

Discounts API

Create and manage discounts, promotions, coupons, and dynamic pricing rules.

Authentication Required

All endpoints require a valid Bearer token with pricing:manage scope for write operations. See Authentication for details.

Overview

AttributeValue
Base Path/api/v1/discounts
AuthenticationBearer Token
Required Rolespos_staff, server, restaurant_staff, restaurant_manager, kitchen, host, tenant_admin, platform_admin, system_admin, super_admin

Discounts

List Discounts

GET /api/v1/discounts

Query Parameters

ParameterTypeDescription
location_iduuidFilter by location
typestringpercentage, fixed, bogo, bundle
statusstringactive, scheduled, expired, disabled
categorystringpromotion, employee, loyalty, coupon

Response

{
"discounts": [
{
"id": "disc_001",
"name": "Happy Hour",
"code": null,
"type": "percentage",
"value": 25,
"category": "promotion",
"status": "active",
"schedule": {
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start_time": "15:00",
"end_time": "18:00"
},
"applies_to": {
"type": "category",
"categories": ["appetizers", "drinks"]
},
"usage": {
"today": 45,
"total": 2850
}
},
{
"id": "disc_002",
"name": "SAVE10",
"code": "SAVE10",
"type": "percentage",
"value": 10,
"category": "coupon",
"status": "active",
"restrictions": {
"minimum_order": 50.00,
"max_uses_total": 1000,
"max_uses_per_customer": 1
},
"usage": {
"remaining": 856,
"total_used": 144
},
"expires_at": "2026-02-28"
}
],
"total": 15
}

Create Discount

POST /api/v1/discounts

Request Body

{
"name": "Weekend Brunch Special",
"code": null,
"type": "percentage",
"value": 15,
"category": "promotion",
"description": "15% off all brunch items on weekends",
"applies_to": {
"type": "category",
"categories": ["brunch"]
},
"schedule": {
"days": ["saturday", "sunday"],
"start_time": "09:00",
"end_time": "14:00"
},
"restrictions": {
"minimum_order": null,
"maximum_discount": 25.00,
"exclude_items": ["mimosa_bottomless"],
"dine_in_only": true
},
"stacking": {
"allowed": false,
"priority": 1
},
"locations": ["loc_123", "loc_456"],
"starts_at": "2026-02-01",
"expires_at": "2026-03-31"
}

Response

{
"id": "disc_003",
"name": "Weekend Brunch Special",
"status": "scheduled",
"starts_at": "2026-02-01",
"created_at": "2026-01-24T19:30:00Z"
}

Get Discount

GET /api/v1/discounts/{discount_id}

Response

{
"id": "disc_001",
"name": "Happy Hour",
"code": null,
"type": "percentage",
"value": 25,
"category": "promotion",
"description": "25% off appetizers and drinks during happy hour",
"status": "active",
"applies_to": {
"type": "category",
"categories": ["appetizers", "drinks"],
"excluded_items": ["premium_whiskey", "wagyu_sliders"]
},
"schedule": {
"days": ["monday", "tuesday", "wednesday", "thursday", "friday"],
"start_time": "15:00",
"end_time": "18:00",
"timezone": "America/New_York"
},
"restrictions": {
"minimum_order": null,
"maximum_discount": 50.00,
"dine_in_only": true,
"bar_area_only": false
},
"stacking": {
"allowed": false,
"priority": 1,
"exclusive_with": ["disc_002", "disc_003"]
},
"locations": ["loc_123"],
"analytics": {
"usage_today": 45,
"usage_this_week": 285,
"usage_total": 2850,
"revenue_impact": -12500.00,
"avg_check_with_discount": 42.50,
"avg_check_without_discount": 38.00
},
"created_at": "2025-06-01T00:00:00Z",
"updated_at": "2026-01-15T00:00:00Z"
}

Update Discount

PUT /api/v1/discounts/{discount_id}

Delete Discount

DELETE /api/v1/discounts/{discount_id}

Coupon Codes

Discount Stacking Rules

By default, discounts cannot be stacked (combined on the same order). Set stacking.allowed: true and configure stacking.priority to control which discounts can combine. Discounts listed in stacking.exclusive_with will never stack together regardless of the allowed setting.

Generate Coupon Code

POST /api/v1/discounts/coupons

Request Body

{
"prefix": "VIP",
"type": "percentage",
"value": 20,
"quantity": 100,
"restrictions": {
"minimum_order": 75.00,
"max_uses_per_code": 1,
"first_order_only": false
},
"valid_from": "2026-02-01",
"valid_until": "2026-02-28",
"campaign": "february_vip_promotion"
}

Response

{
"batch_id": "batch_001",
"codes_generated": 100,
"prefix": "VIP",
"sample_codes": ["VIP-A1B2C3", "VIP-D4E5F6", "VIP-G7H8I9"],
"download_url": "https://...",
"valid_from": "2026-02-01",
"valid_until": "2026-02-28"
}

Validate Coupon Code

POST /api/v1/discounts/coupons/validate

Request Body

{
"code": "SAVE10",
"order": {
"subtotal": 85.00,
"items": [
{"id": "item_001", "category": "entrees", "price": 45.00},
{"id": "item_002", "category": "appetizers", "price": 15.00},
{"id": "item_003", "category": "drinks", "price": 25.00}
]
},
"customer_id": "cust_abc",
"location_id": "loc_123"
}

Response

{
"valid": true,
"code": "SAVE10",
"discount": {
"type": "percentage",
"value": 10,
"calculated_amount": 8.50,
"applies_to_subtotal": 85.00
},
"restrictions_met": {
"minimum_order": true,
"customer_eligible": true,
"within_validity": true,
"uses_remaining": true
},
"message": "Coupon applied: 10% off your order"
}

Redeem Coupon Code

POST /api/v1/discounts/coupons/redeem

Request Body

{
"code": "SAVE10",
"order_id": "ord_12345",
"customer_id": "cust_abc"
}

Promotions

List Active Promotions

GET /api/v1/discounts/promotions/active

Query Parameters

ParameterTypeDescription
location_iduuidFilter by location
order_typestringdine_in, takeout, delivery
timedatetimeCheck for specific time

Response

{
"promotions": [
{
"id": "disc_001",
"name": "Happy Hour",
"description": "25% off appetizers and drinks",
"type": "percentage",
"value": 25,
"applies_to": ["appetizers", "drinks"],
"active_now": true,
"ends_at": "2026-01-24T18:00:00Z"
},
{
"id": "disc_005",
"name": "Free Delivery Friday",
"description": "Free delivery on orders over $30",
"type": "free_delivery",
"minimum_order": 30.00,
"active_now": true,
"order_types": ["delivery"]
}
]
}

Create BOGO Promotion

POST /api/v1/discounts/promotions/bogo

Request Body

{
"name": "BOGO Appetizers",
"description": "Buy one appetizer, get one free",
"buy": {
"quantity": 1,
"category": "appetizers"
},
"get": {
"quantity": 1,
"category": "appetizers",
"discount": 100,
"max_value": 15.00
},
"schedule": {
"days": ["tuesday"],
"all_day": true
},
"restrictions": {
"dine_in_only": true,
"limit_per_table": 2
},
"locations": ["loc_123"],
"starts_at": "2026-02-01"
}

Create Bundle Deal

POST /api/v1/discounts/promotions/bundles

Request Body

{
"name": "Date Night Special",
"description": "2 entrees, 1 appetizer, 1 dessert for $75",
"bundle_price": 75.00,
"items": [
{"category": "entrees", "quantity": 2, "max_price": 35.00},
{"category": "appetizers", "quantity": 1, "max_price": 15.00},
{"category": "desserts", "quantity": 1, "max_price": 12.00}
],
"savings_display": "Save up to $22",
"schedule": {
"days": ["friday", "saturday"],
"start_time": "17:00",
"end_time": "22:00"
},
"dine_in_only": true
}

Employee Discounts

Get Employee Discount

GET /api/v1/discounts/employee/{employee_id}

Response

{
"employee_id": "emp_001",
"discount": {
"type": "percentage",
"value": 50,
"applies_to": "all_items",
"exclusions": ["alcohol", "gift_cards"]
},
"restrictions": {
"max_per_day": 1,
"max_value_per_use": 30.00,
"on_shift_only": false,
"requires_manager_approval": false
},
"family_discount": {
"enabled": true,
"percentage": 25,
"requires_employee_present": true
},
"usage_this_month": {
"count": 8,
"total_value": 125.00
}
}

Apply Employee Discount

POST /api/v1/discounts/employee/apply

Request Body

{
"employee_id": "emp_001",
"order_id": "ord_12345",
"discount_type": "employee",
"pin": "1234"
}

Dynamic Pricing

Get Dynamic Pricing Rules

GET /api/v1/discounts/dynamic-pricing

Response

{
"rules": [
{
"id": "dyn_001",
"name": "Surge Pricing - Peak Hours",
"type": "surge",
"adjustment": {
"type": "percentage",
"value": 15
},
"triggers": {
"occupancy_above": 90,
"wait_time_above_minutes": 30
},
"applies_to": ["delivery"],
"cap": {
"max_adjustment": 25
},
"status": "active"
},
{
"id": "dyn_002",
"name": "Slow Period Discount",
"type": "demand",
"adjustment": {
"type": "percentage",
"value": -10
},
"triggers": {
"occupancy_below": 30,
"time_range": ["14:00", "16:00"]
},
"applies_to": ["dine_in"],
"status": "active"
}
]
}

Create Dynamic Pricing Rule

POST /api/v1/discounts/dynamic-pricing

Analytics

Get Discount Performance

GET /api/v1/discounts/{discount_id}/analytics

Query Parameters

ParameterTypeDescription
periodstringday, week, month

Response

{
"discount_id": "disc_001",
"name": "Happy Hour",
"period": "month",
"usage": {
"total_uses": 2850,
"unique_customers": 1420,
"repeat_rate": 0.35
},
"financial": {
"gross_discount_value": 12500.00,
"incremental_revenue": 8500.00,
"net_impact": -4000.00,
"avg_discount_per_use": 4.39
},
"orders": {
"total_orders_with_discount": 2850,
"avg_order_value_with": 42.50,
"avg_order_value_without": 38.00,
"items_per_order_with": 4.2,
"items_per_order_without": 3.1
},
"conversion": {
"viewed": 5200,
"applied": 2850,
"conversion_rate": 0.55
},
"top_items": [
{"item": "Loaded Nachos", "count": 450},
{"item": "Wings", "count": 380},
{"item": "Margarita", "count": 520}
]
}

Webhooks

EventDescription
discount.createdNew discount created
discount.activatedDiscount became active
discount.expiredDiscount expired
discount.appliedDiscount applied to order
coupon.redeemedCoupon code redeemed
coupon.exhaustedCoupon uses exhausted

Error Responses

StatusCodeDescription
400invalid_codeCoupon code invalid
400minimum_not_metMinimum order not met
404discount_not_foundDiscount ID not found
409already_redeemedCoupon already used by customer
410discount_expiredDiscount has expired
422not_stackableCannot stack with other discounts