Promo Codes

Discount codes, campaigns, and validation

The Promo Codes module manages discount codes for orders and reservations using a flexible discount and condition system.

Data Structure

Promo codes use a nested structure with discounts and conditions arrays for maximum flexibility.

Discount Types

interface Discount {
  type: 'ITEMS_PERCENTAGE' | 'ITEMS_FIXED' | 'SHIPPING_PERCENTAGE';
  marketId: string;    // Market/currency identifier
  bps?: number;        // Basis points for percentage (e.g., 2000 = 20%)
  amount?: number;     // Fixed amount in cents (for ITEMS_FIXED)
}

Condition Types

interface Condition {
  type: 'PRODUCTS' | 'SERVICES' | 'MIN_ORDER_AMOUNT' | 'DATE_RANGE' | 'MAX_USES';
  value: ConditionValue;
}

// ConditionValue varies by type:
// - PRODUCTS/SERVICES: { type: 'IDS', value: string[] }
// - MIN_ORDER_AMOUNT: { type: 'AMOUNT', value: number }
// - MAX_USES: { type: 'COUNT', value: number }
// - DATE_RANGE: { type: 'DATE_RANGE', value: { start?: number, end?: number } }

Create Promo Code

POST /v1/businesses/{businessId}/promo-codes
SDK: sdk.promoCode.createPromoCode()

Create a new promotional code.

// Percentage discount (20% off)
const percentResult = await sdk.promoCode.createPromoCode({
code: 'SUMMER20',
discounts: [
  {
    type: 'ITEMS_PERCENTAGE',
    marketId: 'USD',
    bps: 2000  // 20% = 2000 basis points
  },
  {
    type: 'ITEMS_PERCENTAGE',
    marketId: 'EUR',
    bps: 2000
  }
],
conditions: [
  { type: 'MIN_ORDER_AMOUNT', value: { type: 'AMOUNT', value: 5000 } },
  { type: 'MAX_USES', value: { type: 'COUNT', value: 1000 } },
  { type: 'DATE_RANGE', value: { type: 'DATE_RANGE', value: { start: 1717200000, end: 1725148800 } } }
]
});

// Fixed amount discount ($10 off)
const fixedResult = await sdk.promoCode.createPromoCode({
code: 'SAVE10',
discounts: [
  {
    type: 'ITEMS_FIXED',
    marketId: 'USD',
    amount: 1000  // $10.00 in cents
  }
],
conditions: [
  { type: 'MAX_USES', value: { type: 'COUNT', value: 500 } }
]
});

// Product-specific discount
const productResult = await sdk.promoCode.createPromoCode({
code: 'WIDGETS20',
discounts: [
  {
    type: 'ITEMS_PERCENTAGE',
    marketId: 'USD',
    bps: 2000
  }
],
conditions: [
  { type: 'PRODUCTS', value: { type: 'IDS', value: ['prod_widget1', 'prod_widget2'] } }
]
});

// Service-specific discount
const serviceResult = await sdk.promoCode.createPromoCode({
code: 'FIRSTVISIT',
discounts: [
  {
    type: 'ITEMS_PERCENTAGE',
    marketId: 'USD',
    bps: 1500  // 15% off
  }
],
conditions: [
  { type: 'SERVICES', value: { type: 'IDS', value: ['svc_haircut', 'svc_coloring'] } },
  { type: 'MAX_USES', value: { type: 'COUNT', value: 100 } }
]
});

Parameters

Name Type Description
code required string Promo code string (uppercase recommended)
discounts required Discount[] Array of discount configurations per market
conditions optional Condition[] Array of conditions for code validity

Discount Object

Parameters

Name Type Description
type required ITEMS_PERCENTAGE | ITEMS_FIXED | SHIPPING_PERCENTAGE Discount type
marketId required string Market/currency identifier (e.g., 'USD', 'EUR')
bps optional number Basis points for percentage discount (2000 = 20%)
amount optional number Fixed amount in cents for FIXED type

Condition Object

Parameters

Name Type Description
type required string Condition type (see below)
value required string | number | string[] Condition value

Condition Types:

TypeValue TypeDescription
PRODUCTS{ type: 'IDS', value: string[] }Restrict to specific products
SERVICES{ type: 'IDS', value: string[] }Restrict to specific services
MIN_ORDER_AMOUNT{ type: 'AMOUNT', value: number }Minimum order amount in cents
MAX_USES{ type: 'COUNT', value: number }Total redemption limit
DATE_RANGE{ type: 'DATE_RANGE', value: { start?: number, end?: number } }Valid date range (Unix timestamps)

Get Promo Code

GET /v1/businesses/{businessId}/promo-codes/{id}
SDK: sdk.promoCode.getPromoCode()

Retrieve a promo code by ID.

const result = await sdk.promoCode.getPromoCode({
  id: 'promo_xyz789'
});

console.log(result.code);
console.log(result.discounts);
console.log(result.conditions);
console.log('Uses:', result.currentUses);

Parameters

Name Type Description
id required string Promo code ID

List Promo Codes

GET /v1/businesses/{businessId}/promo-codes
SDK: sdk.promoCode.getPromoCodes()

List all promo codes with filtering.

const result = await sdk.promoCode.getPromoCodes({
query: 'SUMMER',
ids: ['promo_1', 'promo_2'],
statuses: ['ACTIVE'],
sortField: 'createdAt',
sortDirection: 'desc',
cursor: null,
limit: 50,
createdAtFrom: '2024-01-01',
createdAtTo: '2024-12-31'
});

result.items.forEach(promo => {
console.log(promo.code, promo.discounts, promo.conditions);
});

Parameters

Name Type Description
query optional string Search query in code
ids optional string[] Filter by specific promo code IDs
statuses optional string[] Filter by statuses (ACTIVE, INACTIVE)
sortField optional string Sort field
sortDirection optional asc | desc Sort direction
cursor optional string Pagination cursor
limit optional number Items per page
createdAtFrom optional string Filter by creation date (start)
createdAtTo optional string Filter by creation date (end)

Update Promo Code

PUT /v1/businesses/{businessId}/promo-codes/{id}
SDK: sdk.promoCode.updatePromoCode()

Update a promo code.

await sdk.promoCode.updatePromoCode({
id: 'promo_xyz789',
code: 'SUMMER25',  // Change the code
discounts: [
  {
    type: 'ITEMS_PERCENTAGE',
    marketId: 'USD',
    bps: 2500  // Increase to 25%
  }
],
conditions: [
  { type: 'MAX_USES', value: { type: 'COUNT', value: 2000 } },
  { type: 'DATE_RANGE', value: { type: 'DATE_RANGE', value: { end: 1727740800 } } }
]
});

Parameters

Name Type Description
id required string Promo code ID to update
code optional string Updated code string
discounts optional Discount[] Updated discounts
conditions optional Condition[] Updated conditions

Delete Promo Code

DELETE /v1/businesses/{businessId}/promo-codes/{id}
SDK: sdk.promoCode.deletePromoCode()

Delete a promo code.

await sdk.promoCode.deletePromoCode({
  id: 'promo_xyz789'
});

Parameters

Name Type Description
id required string Promo code ID to delete

Using Promo Codes

In E-shop Checkout

Apply promo codes when creating orders or getting quotes:

// Get quote with promo code
const quote = await sdk.eshop.getQuote({
  items: [
    { productId: 'prod_xyz', variantId: 'var_1', quantity: 2 }
  ],
  promoCode: 'SUMMER20'  // Code string
});

console.log('Subtotal:', quote.subtotal);
console.log('Discount:', quote.discount);
console.log('Total:', quote.total);

// Checkout with promo code ID
const result = await sdk.eshop.checkout({
  items: [
    { productId: 'prod_xyz', variantId: 'var_1', quantity: 2 }
  ],
  shippingMethodId: 'ship_standard',
  paymentMethodId: 'pm_card_visa',
  promoCodeId: 'promo_xyz789'  // Promo code ID
});

In Reservations

// Get quote with promo code
const quote = await sdk.reservation.getQuote({
  items: [
    {
      serviceId: 'svc_haircut',
      providerId: 'prv_sarah',
      from: 1704110400,
      to: 1704112200
    }
  ],
  promoCode: 'FIRSTVISIT'  // Code string
});

// Checkout with promo code ID
const result = await sdk.reservation.checkout({
  paymentMethodId: 'pm_card_visa',
  promoCodeId: 'promo_firstvisit123',  // Promo code ID
  blocks: [/* customer info */]
});

Multi-Market Pricing Example

Support multiple currencies with different discount amounts:

const result = await sdk.promoCode.createPromoCode({
  code: 'WELCOME',
  discounts: [
    {
      type: 'ITEMS_FIXED',
      marketId: 'USD',
      amount: 1000  // $10 off in USD
    },
    {
      type: 'ITEMS_FIXED',
      marketId: 'EUR',
      amount: 900   // €9 off in EUR
    },
    {
      type: 'ITEMS_FIXED',
      marketId: 'GBP',
      amount: 800   // £8 off in GBP
    }
  ],
  conditions: [
    { type: 'MAX_USES', value: { type: 'COUNT', value: 100 } },
    { type: 'MIN_ORDER_AMOUNT', value: { type: 'AMOUNT', value: 3000 } }
  ]
});

Basis Points Reference

PercentageBasis Points (bps)
5%500
10%1000
15%1500
20%2000
25%2500
50%5000
100%10000
Tip

Use MAX_USES with a low count for limited campaigns. Combine with SERVICES or PRODUCTS conditions to target specific offerings.