Back to Arky

Promo Codes

Discount codes, campaigns, and validation

The Promo Codes module manages discount codes for product and scheduled services 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

market_key refers to the market key (for example, "us" or "eu"), not a currency code or UUID. Basis points: 2000 = 20%. Fixed amounts are in the minor units of the market’s configured currency.

type Discount =
	| { type: "items_percentage"; market_key: string; bps: number }
	| { type: "items_fixed"; market_key: string; amount: number }
	| { type: "shipping_percentage"; market_key: string; bps: number }
	| {
			type: "audience_percentage";
			audience_id: string;
			tier_ids: string[];
			price_ids: string[];
			bps: number;
	  };

Condition Types

type Condition =
	| { type: "products"; product_ids: string[] }
	| { type: "services"; service_ids: string[] }
	| { type: "min_order_amount"; amount: number }
	| { type: "date_range"; start?: number; end?: number }
	| { type: "max_uses"; count: number }
	| { type: "max_uses_per_user"; count: number };

Create Promo Code

POST /v1/stores/{storeId}/promo-codes
SDK: sdk.eshop.promoCode.createPromoCode()

Create a new promotional code.

// Percentage discount (20% off)
const percentResult = await sdk.eshop.promoCode.createPromoCode({
code: 'SUMMER20',
discounts: [
  {
    type: 'items_percentage',
    market_key: 'us',
    bps: 2000  // 20% = 2000 basis points
  },
  {
    type: 'items_percentage',
    market_key: 'eu',
    bps: 2000
  }
],
conditions: [
  { type: 'min_order_amount', amount: 5000 },
  { type: 'max_uses', count: 1000 },
  { type: 'date_range', start: 1717200000, end: 1725148800 }
]
});

// Fixed amount discount for the "us" market
const fixedResult = await sdk.eshop.promoCode.createPromoCode({
code: 'SAVE10',
discounts: [
{
type: 'items_fixed',
market_key: 'us',
amount: 1000 // 1,000 minor units in the market's configured currency
}
],
conditions: [
{ type: 'max_uses', count: 500 }
]
});

// Product-specific discount
const productResult = await sdk.eshop.promoCode.createPromoCode({
code: 'WIDGETS20',
discounts: [
{
type: 'items_percentage',
market_key: 'us',
bps: 2000
}
],
conditions: [
{ type: 'products', product_ids: ['prod_widget1', 'prod_widget2'] }
]
});

// Service-specific discount
const serviceResult = await sdk.eshop.promoCode.createPromoCode({
code: 'FIRSTVISIT',
discounts: [
{
type: 'items_percentage',
market_key: 'us',
bps: 1500 // 15% off
}
],
conditions: [
{ type: 'services', service_ids: ['svc_haircut', 'svc_coloring'] },
{ type: 'max_uses', count: 100 }
]
});

Parameters

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

Discount Object

Parameters

Name Type Description
type required items_percentage | items_fixed | shipping_percentage | audience_percentage Discount type
market_key required string Market key (e.g. 'us', 'eu')
bps optional number Basis points for percentage discount (2000 = 20%)
amount optional number Fixed amount in the market currency's minor units for items_fixed

Condition Types:

| Type | Fields | Description | | ------------------- | --------------------------------------- | ------------------------------------------------------------------- | | products | product_ids: string[] | Restrict to specific products | | services | service_ids: string[] | Restrict to specific services | | min_order_amount | amount: number | Minimum order amount in the evaluated market currency’s minor units | | max_uses | count: number | Total redemption limit across all contacts | | max_uses_per_user | count: number | Redemption limit per contact | | date_range | start?: number, end?: number | Valid date range (Unix timestamps) |

Get Promo Code

GET /v1/stores/{storeId}/promo-codes/{id}
SDK: sdk.eshop.promoCode.getPromoCode()

Retrieve a promo code by ID.

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

console.log(result.code);
console.log(result.status); // 'active' | 'archived'
console.log(result.discounts);
console.log(result.conditions);
console.log("Uses:", result.uses);

Parameters

Name Type Description
id required string Promo code ID

List Promo Codes

GET /v1/stores/{storeId}/promo-codes
SDK: sdk.eshop.promoCode.getPromoCodes()

List all promo codes for the store, or look up specific codes by ID.

// List all promo codes for the store
const all = await sdk.eshop.promoCode.getPromoCodes({});

all.items.forEach(promo => {
console.log(promo.code, promo.status, promo.uses);
});

// Look up specific promo codes by ID
const specific = await sdk.eshop.promoCode.getPromoCodes({
ids: ['promo_1', 'promo_2']
});

Parameters

Name Type Description
ids optional string[] Filter by specific promo code IDs. When provided, other filters are ignored.

Update Promo Code

PUT /v1/stores/{storeId}/promo-codes/{id}
SDK: sdk.eshop.promoCode.updatePromoCode()

Update a promo code. Use status to archive or re-activate a code.

// Update discounts and conditions
await sdk.eshop.promoCode.updatePromoCode({
id: 'promo_xyz789',
code: 'SUMMER25',  // Change the code
discounts: [
  {
    type: 'items_percentage',
    market_key: 'us',
    bps: 2500  // Increase to 25%
  }
],
conditions: [
  { type: 'max_uses', count: 2000 },
  { type: 'date_range', end: 1727740800 }
]
});

// Archive a promo code
await sdk.eshop.promoCode.updatePromoCode({
id: 'promo_xyz789',
status: 'archived'
});

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
status optional active | archived Promo code status

Delete Promo Code

DELETE /v1/stores/{storeId}/promo-codes/{id}
SDK: sdk.eshop.promoCode.deletePromoCode()

Delete a promo code.

await sdk.eshop.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 to carts before quoting or checkout:

// Get quote with promo code
const cart = await sdk.eshop.cart.current();
await sdk.eshop.cart.update({
	id: cart.id,
	product_items: [{ product_id: "prod_xyz", variant_id: "var_1", quantity: 2 }],
	shipping_method_id: "ship_standard",
	promo_code: "SUMMER20", // Code string
});

const quote = await sdk.eshop.cart.quote({ id: cart.id });

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

// Checkout the same cart
const result = await sdk.eshop.cart.checkout({
	id: cart.id,
	payment_method_key: "credit_card",
});

In Scheduled Services

// Get quote with promo code
const cart = await sdk.eshop.cart.current();
await sdk.eshop.cart.update({
	id: cart.id,
	booking_items: [
		{
			service_id: "svc_haircut",
			provider_id: "prv_sarah",
			slots: [{ from: 1704110400, to: 1704112200 }],
		},
	],
	promo_code: "FIRSTVISIT", // Code string
	forms: [/* contact info */],
});

const quote = await sdk.eshop.cart.quote({ id: cart.id });

// Checkout the same cart
const result = await sdk.eshop.cart.checkout({
	id: cart.id,
	payment_method_key: "credit_card",
});

Multi-Market Pricing Example

Support multiple currencies with different discount amounts:

const result = await sdk.eshop.promoCode.createPromoCode({
	code: "WELCOME",
	discounts: [
		{
			type: "items_fixed",
			market_key: "us",
			amount: 1000, // 1,000 minor units in the "us" market
		},
		{
			type: "items_fixed",
			market_key: "eu",
			amount: 900, // 900 minor units in the "eu" market
		},
		{
			type: "items_fixed",
			market_key: "uk",
			amount: 800, // 800 minor units in the "uk" market
		},
	],
	conditions: [
		{ type: "max_uses", value: { type: "count", value: 100 } },
		{ type: "min_order_amount", value: { type: "amount", value: 3000 } },
	],
});

Basis Points Reference

| Percentage | Basis 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.