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
| Method | Endpoint | Description |
|---|---|---|
| GET | /v1/stores/{store_id}/coupons | List all coupons for the store. |
| GET | /v1/stores/{store_id}/coupons/{id} | Get a specific coupon by ID. |
| POST | /v1/stores/{store_id}/coupons | Create 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/validate | Validate a coupon code and return discount details. |
| GET | /v1/stores/{store_id}/coupon-usage | List coupon usage across orders. |
| GET | /v1/stores/{store_id}/deals | List all deals for the store. |
| GET | /v1/stores/{store_id}/deals/{id} | Get a specific deal by ID. |
| POST | /v1/stores/{store_id}/deals | Create 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
| Field | Type | Description |
|---|---|---|
| id | uuid | Unique identifier for the coupon. |
| code | string | Unique coupon code (e.g., "SUMMER25"). Case-insensitive. |
| type | string | Discount type: "percentage" or "fixed". |
| value | number | Discount value. Percentage (0–100) or fixed amount in cents. |
| min_order_amount | number | Minimum order subtotal in cents for the coupon to apply. |
| max_uses | number | Maximum total redemptions allowed. Null for unlimited. |
| max_uses_per_customer | number | Maximum redemptions per customer. Null for unlimited. |
| usage_count | number | Current number of times this coupon has been redeemed. |
| is_active | boolean | Whether the coupon is currently active. Defaults to true. |
| starts_at | string | ISO 8601 timestamp when the coupon becomes valid. |
| expires_at | string | ISO 8601 timestamp when the coupon expires. Null for no expiration. |
| created_at | string | ISO 8601 timestamp when the coupon was created. |
| updated_at | string | ISO 8601 timestamp of the last modification. |
Deal Fields
| Field | Type | Description |
|---|---|---|
| id | uuid | Unique identifier for the deal. |
| name | string | Display name (e.g., "Buy 2 Get 1 Free"). |
| type | string | Deal type: "buy_x_get_y", "bundle", or "volume". |
| conditions | object | Qualifying conditions (products, quantities, categories). |
| discount | object | Discount configuration (type, value, applies_to). |
| is_active | boolean | Whether the deal is currently active. |
| starts_at | string | ISO 8601 timestamp when the deal becomes valid. |
| expires_at | string | ISO 8601 timestamp when the deal expires. |