Coupons let you offer fixed-amount or percentage discounts to customers. Each coupon can have one or more codes that customers enter at checkout.
Concepts
A Coupon defines the discount rules — type, value, usage limit, validity window, and which items it applies to.
A Coupon Code is the string a customer enters (e.g. TEST50). Multiple
codes can share the same coupon configuration.
Creating a Coupon
Percentage Discount
const { coupon } = await client.coupon.create({
name: 'Early Bird 20%',
kind: 'PERCENT',
discount: 2000, // basis points — 2000 = 20%
filter: 'EVENTS',
events: [{ id: 'evt_01jps5cgsenjrazw6wswmyspa3' }],
limit: 100,
saleStartsAt: '2025-01-01T00:00:00',
saleEndsAt: '2025-02-01T00:00:00',
teamId: 'team_456',
});
Fixed Amount Discount
const { coupon } = await client.coupon.create({
name: '$10 Off',
kind: 'AMOUNT',
discount: 1000, // cents — 1000 = $10.00
currency: 'AUD',
filter: 'TEAM',
limit: -1, // unlimited
saleStartsAt: '2025-01-01T00:00:00',
teamId: 'team_456',
});
Coupon Fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Internal label |
kind | string | Yes | PERCENT (basis points) or AMOUNT (cents) |
discount | number | Yes | Discount value (see kind) |
currency | string | AMOUNT only | ISO 4217 currency code |
filter | string | Yes | Scope: TEAM, PROMOTER, EVENTS, SECTIONS, or ADMISSIONS |
limit | number | Yes | Max redemptions (-1 for unlimited) |
saleStartsAt | string | Yes | Start of validity window (ISO 8601, no timezone) |
saleEndsAt | string | No | End of validity window |
teamId | string | Yes | Owning team |
events | array | No | Event IDs (when filter is EVENTS) |
sections | array | No | Section IDs (when filter is SECTIONS) |
admissions | array | No | Admission IDs (when filter is ADMISSIONS) |
promoters | array | No | Promoter IDs (when filter is PROMOTER) |
Filter Scopes
| Filter | Applies to |
|---|---|
TEAM | All events in the team |
PROMOTER | All events by the specified promoters |
EVENTS | Only the specified events |
SECTIONS | Only the specified sections |
ADMISSIONS | Only the specified admissions |
Managing Codes
Add one or more codes to a coupon:
const { couponCode } = await client.coupon.code.create({
couponId: 'cpn_01jps5cgsfzs1ksqaet5hba8ac',
name: 'TEST50',
active: true,
teamId: 'team_456',
});
Code names must be unique within a team.
List codes for a coupon:
const { couponCodes } = await client.coupon.code.list({
couponId: 'cpn_01jps5cgsfzs1ksqaet5hba8ac',
});
Deactivate a code without deleting it:
await client.coupon.code.update({
id: 'code_789',
active: false,
});
Applying a Coupon to an Order
Pass the code string when creating an order or requesting a quote:
// Preview the discount
const { quote } = await client.order.quote({
eventId: 'evt_01jps5cgsenjrazw6wswmyspa3',
items: [{ admissionId: 'adm_01jps5cgsee0xvapbk92e8eb4g', quantity: 2 }],
couponCode: 'TEST50',
});
console.log(quote.price.discount); // negative value in cents
console.log(quote.price.total); // total after discount
// Apply at order creation
const { order } = await client.order.create({
eventId: 'evt_01jps5cgsenjrazw6wswmyspa3',
items: [{ admissionId: 'adm_01jps5cgsee0xvapbk92e8eb4g', quantity: 2 }],
couponCode: 'TEST50',
returnUrl: 'https://yoursite.com/order/complete',
});
Validation Rules
The API validates the coupon when applied:
- The code must be active
- The parent coupon must be active
- The current time must be within the validity window
- The coupon must not have exceeded its usage limit
- The coupon’s filter must match the items in the order
If validation fails, the API returns a 400 Bad Request with details.
Usage Tracking
Each coupon tracks how many times it has been redeemed:
const { coupon } = await client.coupon.get({ id: 'cpn_01jps5cgsfzs1ksqaet5hba8ac' });
console.log(coupon.uses); // current redemptions
console.log(coupon.limit); // max allowed (-1 = unlimited)
Usage is tracked at both the coupon and code level. When a coupon has a limited number of uses, they are consumed on a first-come, first-served basis across all codes.