skills/pricing-promotions/coupon-management/SKILL.md
Build a coupon system with percentage and fixed discounts, usage limits per customer, expiration dates, and bulk unique-code generation
npx skillsauth add finsilabs/awesome-ecommerce-skills coupon-managementInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Coupon systems let merchants create promotional codes with configurable rules: percentage or fixed-amount discounts, minimum order requirements, usage limits per coupon or per customer, and expiration dates. Every major e-commerce platform includes a built-in coupon system — you almost never need to build one from scratch. This skill walks you through setting up coupon management on each platform and explains when to reach for an app or plugin for advanced requirements like bulk unique codes or campaign tracking.
| Platform | Built-in Capability | When to Add an App/Plugin | |----------|-------------------|--------------------------| | Shopify | Shopify Discounts — supports percentage, fixed amount, free shipping, BOGO; usage limits, expiry, minimum purchase | When you need bulk unique codes (Shopify supports import), customer-group-specific coupons, or loyalty integration (Smile.io, LoyaltyLion) | | WooCommerce | WooCommerce Coupons — built into core; percentage, fixed cart, fixed product, free shipping types | When you need bulk unique code generation: WooCommerce Smart Coupons plugin; advanced rules: YITH WooCommerce Dynamic Pricing & Discounts | | BigCommerce | Coupon codes built in — percentage, fixed amount, free shipping, free product types | When you need B2B-specific codes or advanced restrictions; BigCommerce app marketplace has options like Coupon Manager Pro | | Custom / Headless | Must build — see Custom section below | N/A — you are building the system |
SUMMER20) or click Generate code for a random oneBulk unique codes on Shopify:
Shopify Plus — Shopify Scripts for advanced stacking:
Bulk unique codes on WooCommerce:
Bulk codes on BigCommerce:
Use the BigCommerce Promotions API (POST /v2/coupons) to generate codes programmatically, then export for distribution.
For headless stores, you need to build the validation and redemption logic. The key requirements are atomic redemption (prevent race conditions when two customers use the last available redemption simultaneously) and idempotent order processing.
// Coupon validation at checkout
async function validateCoupon(
code: string,
customerId: string,
orderSubtotalCents: number
): Promise<{ valid: boolean; discountCents: number; error?: string }> {
const coupon = await db.coupons.findOne({ code: code.toUpperCase().trim(), is_active: true });
if (!coupon) return { valid: false, discountCents: 0, error: 'Code not found' };
const now = new Date();
if (coupon.expires_at && coupon.expires_at < now) return { valid: false, discountCents: 0, error: 'Code expired' };
if (coupon.usage_limit && coupon.usage_count >= coupon.usage_limit) return { valid: false, discountCents: 0, error: 'Code fully used' };
if (coupon.min_order_cents && orderSubtotalCents < coupon.min_order_cents) return { valid: false, discountCents: 0, error: `Minimum order $${coupon.min_order_cents / 100}` };
// Per-customer limit check
if (coupon.per_customer_limit) {
const uses = await db.couponRedemptions.count({ coupon_id: coupon.id, customer_id: customerId });
if (uses >= coupon.per_customer_limit) return { valid: false, discountCents: 0, error: 'Already used' };
}
const discountCents = coupon.type === 'percentage'
? Math.round(orderSubtotalCents * (coupon.value / 100))
: Math.min(coupon.value_cents, orderSubtotalCents);
return { valid: true, discountCents };
}
// Atomic redemption — use inside the order creation transaction
async function redeemCoupon(tx: Tx, couponId: string, customerId: string, orderId: string, discountCents: number) {
// Atomic increment with guard — prevents over-redemption under concurrency
const result = await tx.raw(
`UPDATE coupons SET usage_count = usage_count + 1
WHERE id = ? AND (usage_limit IS NULL OR usage_count < usage_limit)
RETURNING id`,
[couponId]
);
if (result.rowCount === 0) throw new Error('COUPON_EXHAUSTED');
await tx.couponRedemptions.insert({ coupon_id: couponId, customer_id: customerId, order_id: orderId, discount_cents: discountCents });
}
Bulk code generation for email campaigns:
import crypto from 'crypto';
function generateCode(prefix = 'PROMO', length = 8): string {
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; // no ambiguous chars
return prefix + '-' + Array.from(crypto.randomBytes(length))
.map(b => chars[b % chars.length]).join('');
}
async function bulkGenerate(template: CouponTemplate, quantity: number): Promise<string[]> {
const codes: string[] = [];
while (codes.length < quantity) {
const batch = Array.from({ length: Math.min(500, quantity - codes.length) }, () => generateCode(template.prefix));
const inserted = await db.coupons.insertMany(
batch.map(code => ({ ...template, code, usage_limit: 1, per_customer_limit: 1 })),
{ onConflict: 'ignore' }
);
codes.push(...inserted.map(r => r.code));
}
return codes;
}
| Problem | Solution |
|---------|----------|
| Two customers redeem the last use simultaneously | Use atomic UPDATE ... WHERE usage_count < usage_limit and verify rowCount === 1 (custom builds); platforms handle this natively |
| Coupon still valid after order cancellation | Decrement the usage count when an order is cancelled or refunded; Shopify does this automatically |
| Per-customer limit bypassed with multiple accounts | Supplement customer-ID checks with email checks; for high-value campaigns, require verified phone numbers |
| Bulk-generated codes collide with existing ones | Use INSERT ... ON CONFLICT DO NOTHING and regenerate collisions until target quantity is met |
| Free-shipping coupon stacks with a percentage discount unexpectedly | Define your stacking policy explicitly; on Shopify, use the "Can be combined with" settings on each discount |
tools
Let shoppers save products to a wishlist, share it with friends, and get notified when saved items come back in stock or drop in price
development
Build a themeable storefront with design tokens and CSS custom properties that supports white-labeling, multi-brand variants, and dark mode
development
Speed up product discovery with instant search suggestions, fuzzy typo matching, and category-aware results powered by Algolia or Elasticsearch
development
Build a mobile-first storefront with thumb-friendly navigation, sticky add-to-cart buttons, and touch-optimized components for high mobile conversion