Back to Developer

Coupons & Discounts

Create coupon codes, configure percentage or fixed discounts, set usage limits, and build automatic deals.

Overview

Coupons let you offer percentage or fixed-amount discounts through shareable codes. Each coupon can have a maximum number of total uses, per-customer limits, minimum order requirements, and an expiration date. Coupons are validated at checkout and automatically applied to the order total.

Deals provide automatic discounts based on cart conditions — buy-X-get-Y, volume pricing, and bundle discounts. Unlike coupons, deals are applied automatically when the cart meets the qualifying conditions without requiring a code.

Create a Coupon

Create a coupon with a unique code, discount type, value, and optional constraints. Percentage coupons accept values from 0 to 100. Fixed coupons use amounts in cents.

const whale = new WhaleClient({ apiKey: 'wk_live_...' })

// Create a 25% off coupon with usage limits
const coupon = await whale.coupons.create({
  code: 'SUMMER25',
  type: 'percentage',
  value: 25,
  max_uses: 100,
  max_uses_per_customer: 1,
  min_order_amount: 5000,  // $50.00 minimum
  expires_at: '2026-09-01T00:00:00.000Z'
})

// Response
{
  "id": "cpn_550e8400-e29b-41d4-a716-446655440000",
  "code": "SUMMER25",
  "type": "percentage",
  "value": 25,
  "max_uses": 100,
  "max_uses_per_customer": 1,
  "min_order_amount": 5000,
  "usage_count": 0,
  "is_active": true,
  "starts_at": null,
  "expires_at": "2026-09-01T00:00:00.000Z",
  "created_at": "2026-03-10T12:00:00.000Z",
  "updated_at": "2026-03-10T12:00:00.000Z"
}

// Create a fixed-amount coupon ($10 off)
const fixed = await whale.coupons.create({
  code: 'SAVE10',
  type: 'fixed',
  value: 1000,  // $10.00 in cents
  max_uses: null  // unlimited uses
})

// List all active coupons
const coupons = await whale.coupons.list()
// { data: [...], total: 2 }

Validate a Coupon

Validate a coupon code before applying it at checkout. The API checks whether the coupon exists, is active, has not expired, and has remaining uses. It returns the discount amount for a given order subtotal.

const whale = new WhaleClient({ apiKey: 'wk_live_...' })

// Validate a coupon code
const result = await whale.coupons.validate('SUMMER25', {
  subtotal: 12000  // $120.00 order
})

// Valid coupon
{
  "is_valid": true,
  "code": "SUMMER25",
  "discount_type": "percentage",
  "discount_value": 25,
  "discount_amount": 3000,  // $30.00 off
  "reason": null
}

// Expired coupon
const expired = await whale.coupons.validate('OLD_CODE')
{
  "is_valid": false,
  "code": "OLD_CODE",
  "discount_type": null,
  "discount_value": null,
  "discount_amount": 0,
  "reason": "Coupon has expired."
}

// Below minimum order amount
const tooSmall = await whale.coupons.validate('SUMMER25', {
  subtotal: 2000  // $20.00 — below $50 minimum
})
{
  "is_valid": false,
  "code": "SUMMER25",
  "discount_type": "percentage",
  "discount_value": 25,
  "discount_amount": 0,
  "reason": "Order subtotal must be at least $50.00."
}

Deals

Deals are automatic promotions that apply when cart conditions are met. They support buy-X-get-Y, bundle discounts, and volume pricing. Deals do not require a coupon code — they are evaluated automatically during checkout.

const whale = new WhaleClient({ apiKey: 'wk_live_...' })

// Buy 2, Get 1 Free
const deal = await whale.deals.create({
  name: 'Buy 2 Get 1 Free — T-Shirts',
  type: 'buy_x_get_y',
  conditions: {
    product_ids: ['prod_abc123', 'prod_def456'],
    buy_quantity: 2
  },
  discount: {
    type: 'percentage',
    value: 100,          // 100% off the free item
    get_quantity: 1,
    applies_to: 'cheapest'
  },
  starts_at: '2026-03-10T00:00:00.000Z',
  expires_at: '2026-04-10T00:00:00.000Z'
})

// Volume discount — 10% off orders of 5+ items
const volume = await whale.deals.create({
  name: 'Bulk Order Discount',
  type: 'volume',
  conditions: {
    min_quantity: 5,
    category_ids: ['cat_shirts']
  },
  discount: {
    type: 'percentage',
    value: 10
  }
})

// List active deals
const deals = await whale.deals.list({ is_active: true })
// { data: [...], total: 2 }

Usage Tracking

Every time a coupon or deal is redeemed, a usage record is created linking the discount to the order and customer. Use the usage endpoint to track redemption history, measure campaign performance, and identify top customers.

const whale = new WhaleClient({ apiKey: 'wk_live_...' })

// View usage for a specific coupon
const usage = await whale.couponUsage.list({
  coupon_id: 'cpn_550e8400...'
})

// Response
{
  "data": [
    {
      "id": "cu_001",
      "coupon_id": "cpn_550e8400...",
      "order_id": "ord_abc123",
      "customer_id": "cust_def456",
      "discount_amount": 3000,
      "redeemed_at": "2026-03-10T14:30:00.000Z"
    },
    {
      "id": "cu_002",
      "coupon_id": "cpn_550e8400...",
      "order_id": "ord_ghi789",
      "customer_id": "cust_jkl012",
      "discount_amount": 1500,
      "redeemed_at": "2026-03-10T15:45:00.000Z"
    }
  ],
  "total": 2
}

// Check the coupon's current usage count
const coupon = await whale.coupons.get('cpn_550e8400...')
// { usage_count: 2, max_uses: 100, ... }

API Reference

MethodEndpointDescription
GET/v1/stores/{store_id}/couponsList all coupons for the store.
GET/v1/stores/{store_id}/coupons/{id}Get a specific coupon by ID.
POST/v1/stores/{store_id}/couponsCreate a new coupon.
PATCH/v1/stores/{store_id}/coupons/{id}Update an existing coupon.
DELETE/v1/stores/{store_id}/coupons/{id}Deactivate a coupon.
POST/v1/stores/{store_id}/coupons/validateValidate a coupon code and return discount details.
GET/v1/stores/{store_id}/coupon-usageList coupon usage across orders.
GET/v1/stores/{store_id}/dealsList all deals for the store.
GET/v1/stores/{store_id}/deals/{id}Get a specific deal by ID.
POST/v1/stores/{store_id}/dealsCreate a new deal.
PATCH/v1/stores/{store_id}/deals/{id}Update an existing deal.
DELETE/v1/stores/{store_id}/deals/{id}Deactivate a deal.

Coupon Fields

FieldTypeDescription
iduuidUnique identifier for the coupon.
codestringUnique coupon code (e.g., "SUMMER25"). Case-insensitive.
typestringDiscount type: "percentage" or "fixed".
valuenumberDiscount value. Percentage (0–100) or fixed amount in cents.
min_order_amountnumberMinimum order subtotal in cents for the coupon to apply.
max_usesnumberMaximum total redemptions allowed. Null for unlimited.
max_uses_per_customernumberMaximum redemptions per customer. Null for unlimited.
usage_countnumberCurrent number of times this coupon has been redeemed.
is_activebooleanWhether the coupon is currently active. Defaults to true.
starts_atstringISO 8601 timestamp when the coupon becomes valid.
expires_atstringISO 8601 timestamp when the coupon expires. Null for no expiration.
created_atstringISO 8601 timestamp when the coupon was created.
updated_atstringISO 8601 timestamp of the last modification.

Deal Fields

FieldTypeDescription
iduuidUnique identifier for the deal.
namestringDisplay name (e.g., "Buy 2 Get 1 Free").
typestringDeal type: "buy_x_get_y", "bundle", or "volume".
conditionsobjectQualifying conditions (products, quantities, categories).
discountobjectDiscount configuration (type, value, applies_to).
is_activebooleanWhether the deal is currently active.
starts_atstringISO 8601 timestamp when the deal becomes valid.
expires_atstringISO 8601 timestamp when the deal expires.