Base: https://api.sajilosport.com/api

Coupons / Promo codes

Base paths: /api/coupons (customer) and /api/admin/coupons (admin)

Apply-on-booking is server-side. The app may preview a discount via validate, but the booking create path re-validates, locks the coupon, writes coupon_usages, and sets discount_amount / total_amount. Payment initiate always charges booking.total_amount.


Flow

1. Venue owner creates a coupon for one venue

2. App: GET /coupons → all live venue deals; GET /coupons?venue_id= → that venue only

3. App: POST /coupons/validate { code, amount, venue_id } → preview discount

4. App: POST /bookings { …, coupon_code } → server applies discount + records usage

5. App: POST /payments/initiate → pays the discounted total

6. Cancel unpaid booking → coupon usage released so the code can be reused


GET /api/coupons

QueryBehavior
_(none)_All active venue deals
venue_idThat venue’s active coupons only

POST /api/coupons/validate [Auth]

{ "code": "SAVE200", "amount": 1500, "venue_id": 1 }

Venue-scoped coupons require venue_id. Response includes discount_amount / final_amount.


POST /api/bookings [Auth]

{
  "court_id": 1,
  "date": "2026-08-27",
  "start_time": "10:00",
  "end_time": "11:00",
  "coupon_code": "SAVE200"
}

Server computes pricing, applies coupon (if present), returns booking with discount_amount and reduced total_amount.


Admin CRUD — /api/admin/coupons

MethodNotes
GET /?per_page=&venue_id=Owners: own venues. Super: all / filter
POST /venue_id is required. Percent value ≤ 100. Code uppercased
PUT /{coupon}value, valid_until, is_active, usage_limit
DELETE /{coupon}Soft ownership via policy

Rules

  • One use per user per coupon (unique coupon_id + user_id)
  • usage_limit / used_count enforced under row lock on apply
  • Unpaid cancel releases usage and decrements used_count
  • Client-supplied discount amounts are ignored