> ## Documentation Index
> Fetch the complete documentation index at: https://docs.1club.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Promotions

> Create vouchers and discounts with schedules, codes, audience targeting, and usage caps

Promotions are time-bound offers. They come in two flavours - **Vouchers** credit a member's wallet when the member redeems a code, and **Discounts** reduce the price of a booking or product order at checkout. Both share the same controls for scheduling, codes, redemption caps, audience targeting and scope. Owners and managers create promotions, staff can apply them on a member's behalf, and members redeem them in the portal or at checkout.

## When to use it

Promotions let you change a price for a purpose - winning new members, filling quiet hours, or bringing people back - without touching your everyday prices. Each one can be scheduled, capped, and tracked in promotion analytics.

Typical uses:

* **Build a trial or intro offer** - an auto-apply discount on a plan lands at checkout for first-time buyers with no code, and the plan card shows a badge like **Try free** or **Save 20%**.
* **Fill quiet court hours** - a padel gym gives a second hour free on 2-hour daytime court bookings, and the booking calendar advertises the offer to members.
* **Bring lapsed members back** - target a "lapsed" tag with a voucher code that adds credit to the member's wallet.
* **Reward group bookings** - a discount that applies only when someone books a class for three or more people.

See [Auto-apply](#auto-apply-trials-and-intro-offers) for trials and [Example: 2 hours for the price of 1 on daytime courts](#example-2-hours-for-the-price-of-1-on-daytime-courts) for the court offer.

## Vouchers vs. discounts

Promotions are always one of two types. Pick the type when you create the promotion; you cannot change it afterwards.

| | Voucher | Discount |
| - | - | - |
| **What it does** | Adds credit to the member's wallet | Reduces the price at checkout |
| **Who triggers it** | The member (or staff on their behalf) | Applied automatically or by entering a code at checkout |
| **Value format** | Fixed amount only | Percentage **or** fixed amount |
| **Where the code is entered** | Member portal: **Account** > **Add voucher** | Booking dialog or order checkout |
| **Can be scoped to a class/area/instructor?** | No - wallet credit is universal | Yes (see **Scope** below) |
| **Effect on the ledger** | Creates a wallet transaction | Reduces the booking/order total |
| **Auto-apply at checkout** | No | Yes - see [Auto-apply](#auto-apply-trials-and-intro-offers) |
| **Can target a specific plan?** | No | Yes - via **Plan** in the Valid for section |

## Creating a promotion

1. Go to **Sales** > **Promotions** (`/marketing/promotions`). Promotions moved here from **Marketing**, so old links still work.
2. Click **Add Promotion** and choose **Voucher** or **Discount** as the type.
3. Fill in:
   * **Name** - shown to staff, on the member-facing receipt and, for an auto-apply discount, on your booking calendar beside the discounted price (for example "Buy 1 get 1"). Use the translate button next to the field to give it a name in every language your site supports.
   * **Code** *(optional)* - what members type. Codes are normalised to UPPERCASE and must be unique within the organization. If you leave it blank, the promotion can still be applied by staff from the dashboard but won't have a code to share.
   * **Description** - shown to members where the promotion appears.
   * **Value** - for vouchers, the credit amount; for discounts, either a percentage (max 100) or a fixed amount, depending on **Discount format**.
4. Set the active window, caps, visibility, audience and scope (see below).
5. **Save.**

## Scheduling (active window)

Each promotion has an optional **Starts at** and **Ends at**. The list view shows a status badge:

* **Scheduled** - created but the start time hasn't passed yet. Codes won't validate.
* **Live** - within the active window. Available to redeem.
* **Ended** - past the end time. Codes return an "expired" reason and the promotion stops accruing redemptions.

Leaving both fields empty makes the promotion live indefinitely.

## Usage caps

Two independent limits control how often a promotion can be redeemed:

* **Max redemptions** - total across all members. Once reached, the promotion stops working for everyone.
* **Max redemptions per member** - how many times a single member can use it. Must be less than or equal to the global cap.

If a booking that consumed a promotion is later cancelled, the redemption is rolled back automatically - the global counter decrements and the member's per-member allowance is freed.

## Visibility

Controls where the promotion shows up in the member portal:

* **Public** - listed publicly (e.g. signup flow), visible to non-members.
* **Member-only** - visible to signed-in members.
* **Private** - never listed; can only be applied by typing the code or by staff action. Use this for codes you distribute through email, social, or partner channels.

## Audience targeting (segment filter)

Restrict who can redeem by:

* **Member types** - only contacts of these types can redeem.
* **Tags** - only contacts carrying at least one of these tags.

Within a list the match is **OR** (any tag matches). Between lists it's **AND** (the member must match both the type filter and the tag filter when both are set). Leave both empty to allow everyone in the audience defined by **Visibility**.

## Scope (valid for) - discounts only

A discount can target two independent surfaces. List entries on either surface; the discount is valid when the purchase matches **any** declared surface.

**Plan surface - what plan is being purchased:**

* **Plan** - the discount applies only when the buyer is purchasing one of the selected plans. Used for first-purchase intro pricing, trials, and plan-specific promo codes. Required for [auto-apply](#auto-apply-trials-and-intro-offers).

**Booking surface - what is being booked:**

* **Class types** - applies only when the booking is for one of these class types.
* **Area types** - applies only when the booking targets one of these area types.
* **Instructor types** - applies only when the assigned instructor is one of these types.
* **Clubs** - applies only to bookings at the selected gyms. Leave empty for every gym. Use it when two of your gyms share the same area type but the offer is for one of them.

A promotion with both surfaces (e.g. "Plan: Annual + Class types: Yoga") applies to purchases of the listed plans **and** to bookings of the listed class types. Leaving every surface empty makes the discount valid for any booking or order (but never for a plan purchase, since plan eligibility is opt-in).

Vouchers are wallet credit, so they aren't scoped - once a voucher is redeemed the credit can be spent on anything the wallet can pay for.

## Auto-apply (trials and intro offers)

A discount can be set to **Auto-apply**, meaning it lands silently at checkout for any first-time buyer of the targeted plan. No code needed. This is how you build trials, free days, and first-month-off offers.

### How it works

1. Create a **Discount** promotion.
2. Pick one or more plans in **Valid for** > **Plan**. Auto-apply requires at least one eligible plan or booking scope; the trial and intro-offer use cases below are all plan-based.
3. Set **Value** to the discount you want (100% for a free trial, e.g. 50 for "50% off the first period").
4. Toggle **Auto-apply** on.
5. Save.

From then on, anyone buying one of those plans **for the first time** automatically gets the discount applied to the membership creation transaction. No code entry, no admin step.

### First-time buyer rule

Auto-apply only fires for a contact who has **no prior membership** on any of the targeted plans - active, expired, or cancelled. Once they've ever held a membership on one of those plans, they no longer qualify. This prevents the same person re-triggering an intro offer by signing up again.

When more than one auto-apply promotion could fire for the same plan and contact, the one with the **largest computed savings** wins. Only one applies.

### How it shows up on plan cards

The public plan API computes a `firstTimeOffer` for each plan and contact, which the member-facing apps use to render badges like **"Try free"** or **"Save 20%"** on plan cards. The card shows both the original price and the effective price after the discount.

### Effect on recurring plans

For recurring plans the discount is baked into the membership's stored price at creation, so it **carries through every renewal** for as long as that membership runs. If you want the discount to lapse after the first period, use a one-time plan or a recurring plan paired with a manual price change at the renewal you choose.

### Voucher promotions can't auto-apply

Vouchers credit the wallet; they have no checkout-time line to silently discount. The Auto-apply toggle is hidden when **Type** is **Voucher**.

## Attaching promotions to a plan

The plan detail page (**Sales** > **Plans**, then open a plan) has a **Promotions** section listing every promotion whose **Valid for** > **Plan** includes this plan. From there you can:

* **Add promotion** - opens the promotion editor pre-scoped to this plan. Pick the shape you want: 100% auto-apply (trial), code-driven percentage off, fixed-amount intro, etc.
* **Edit** any attached promotion in place.
* **Delete** an attached promotion if it has no redemptions yet.

This is the most common entry point when you're building a trial for a specific plan rather than running a cross-product campaign.

## Conditions

You can also require a checkout context before a discount applies. The **Conditions** section of the promotion has:

* **Minimum people** - the discount applies only when the class booking party has at least that many people (minimum 2). Use it to reward group bookings - for example, a discount that kicks in only when someone books a class for three or more. Leave it empty for no people requirement. See [Party bookings](/schedule/classes) for how party sizes work.
* **Only at certain times** - days (optional; empty means every day) plus a start and end time, read on the gym's clock. Choose how the booking must match the window:
  * **Starts in the window** - the whole booking qualifies when it starts inside the window. A 15:00 booking that runs to 17:00 qualifies for an 8:00 to 16:00 offer. This is what most offers mean by "book between 8:00 and 16:00".
  * **Fits entirely in the window** - the booking must start and end inside the window.
* **Minimum length** and **Maximum length** - in minutes. Set both to the same value to target one length exactly, for example 120 for a "2 for 1" offer.

The time window and the booking length judge the whole booking: the discount applies to a booking or it does not. They are never split at the window's edges the way a [pricing rule](/settings/pricing-rules) band is.

## Time-of-day offers on the booking calendar

An auto-apply discount with booking conditions is shown to members on your booking calendar before they check out:

* A line under the calendar names the offer and its hours, for example "Buy 1 get 1 - 08:00 to 16:00".
* When a member picks a booking that qualifies, the regular price is struck through, the discounted total is shown, and the promotion's name appears beside it.
* When a member picks a shorter booking and a longer one would qualify, one line under the duration tells them - "Buy 1 get 1 - 2 h for the price of 1" - and tapping it switches to the longer booking. If the longer booking costs more, the line shows its price instead.

Signed-in members see offers they qualify for. Visitors who are not signed in don't see offers limited by an audience or to a first booking, because the calendar can't check who they are. They do see offers with a per-member limit: that limits how often someone uses an offer, not who gets it, and it is checked again when they sign in to book. Checkout always has the final say.

### Example: 2 hours for the price of 1 on daytime courts

A padel gym wants a second hour free on daytime bookings at one of its gyms:

1. Create a **Discount** with **Discount format** set to percentage and **Value** 50.
2. Name it "Buy 1 get 1" and translate the name if your site has more than one language.
3. In **Valid for**, switch to **Selected bookings**, turn on **Areas** and pick your court type. Under **Clubs**, pick the gym running the offer. An auto-apply discount needs at least one booking type, so **All bookings** can't be saved with **Auto-apply** on.
4. Under **Conditions**, turn on **Only at certain times** and set 08:00 to 16:00 with **Starts in the window**, and set **Minimum length** and **Maximum length** both to 120. Leave the days empty for every day.
5. Turn on **Auto-apply** and save.

A 2-hour booking at 10:00 that normally costs 56 is shown - and charged - at 28. A 1-hour booking stays at its regular price, and the calendar offers the second hour for free.

### Courts booked with a coach

When a court and a coach are booked together as one booking, a discount valid only for areas takes its amount off the court's share and leaves the coach's fee untouched. A discount valid for both areas and instructors applies to the whole booking.

## Stacking

Only **one** promotion can be applied per booking or order. Discounts don't stack with other discounts, and a voucher's wallet credit is paid out at checkout independently of any discount applied to the same order.

## How members redeem

### Vouchers

1. Member signs into the portal and opens **Account**.
2. Taps **Add voucher** and enters the code.
3. The credit is added to their wallet immediately and recorded as a wallet transaction labelled with the promotion name.

The wallet balance can then be spent at checkout the next time they book a class or buy a product.

### Discount codes

Members enter a discount code during checkout (booking or product order). The portal validates it live, shows the resulting savings, and applies it when they submit. Invalid codes return a generic error on the member side - this is intentional, to prevent code-guessing. Staff using the admin dashboard see the specific reason (see **Validation reasons** below).

## Staff redemption

Staff can apply promotions on a member's behalf:

* **Vouchers** - open the contact and use **Redeem voucher**. Enter the code; the credit posts to their wallet.
* **Discounts** - when creating a booking or order in the admin, paste the code into the promotion field on the dialog. The dashboard validates it inline and tells you why a code is rejected if it is.
* **Discounts in the booking dialog** - **Add discount** lists every discount; the ones that don't fit this booking are greyed out. A time-of-day or booking-length discount becomes selectable once the booking's time and length match it, and the amount shown is what checkout will take off - for a court booked with a coach and a courts-only discount, that is the court's share only.

## Analytics

On **Sales** > **Promotions**, click **View Analytics** to open the promotions dashboard, where you'll find:

* KPI cards: total promotions, live promotions, total redemptions, credit issued, discount given.
* Breakdown of redemptions by promotion type.
* A redemption-over-time trend.
* A per-promotion summary table with uses, revenue impact, discount given, members acquired, and average order value.
* A per-member summary showing who redeemed which promotion, how many times, and the cumulative amount.

## Retiring a promotion

* **Promotions with no redemptions** can be deleted outright.
* **Promotions that have ever been redeemed** cannot be deleted - this preserves the audit trail on past bookings and wallet transactions. To stop them being used, set **Ends at** to a time in the past (or to now). The status badge becomes **Ended** and validation returns "expired".

## Validation reasons (admin reference)

When validating a code in the admin (for example, on a booking dialog) you may see one of these reasons. Members see a single generic "invalid code" message, except when the code needs more people, a different time or a different booking length - those they can fix, so they are told.

* **not\_found** - code doesn't exist in this organization.
* **not\_started** - the active window hasn't begun.
* **expired** - past the end time.
* **max\_redemptions\_reached** - global cap hit.
* **max\_redemptions\_per\_contact\_reached** - this member has used it as many times as allowed.
* **member\_type\_mismatch** - the contact's type isn't in the segment filter.
* **tag\_mismatch** - the contact has none of the required tags.
* **class\_type\_not\_eligible** - discount is scoped to class types and this booking isn't one of them.
* **area\_type\_not\_eligible** - discount is scoped to area types and this area isn't one of them.
* **instructor\_type\_not\_eligible** - discount is scoped to instructor types and this instructor isn't one of them.
* **plan\_not\_eligible** - discount is scoped to specific plans and this plan isn't one of them. Also fires when the buyer is purchasing a plan and the promotion has no plan rule set (plan eligibility is opt-in).
* **booking\_not\_eligible** - the booking-surface scope is set but the booking doesn't satisfy it (catch-all when the granular reason can't be narrowed).
* **scope\_not\_eligible** - the promotion declares both plan and booking surfaces, and neither matches.
* **club\_not\_eligible** - the discount is limited to some gyms and this booking is at another one.
* **time\_not\_eligible** - the booking does not start in (or fit inside) the promotion's time of day.
* **duration\_not\_eligible** - the booking is shorter or longer than the promotion's booking length.
* **not\_first\_time\_buyer** - an auto-apply discount was evaluated for a contact who already holds (or held) a membership on one of the targeted plans.
* **wrong\_type** - a voucher code was entered at checkout (vouchers credit the wallet; they aren't applied as a discount).

## Best practices

* **Cap per-member use** for codes you intend to share publicly. A per-member limit of 1 prevents the same member redeeming a public code repeatedly.
* **Prefer Ends at over deletion.** Setting an end date is reversible and keeps the redemption history intact.
* **Use segment filters for re-engagement campaigns.** Combine a "lapsed" tag with a generous voucher to bring members back.
* **Scope discounts to fill specific inventory.** A 30% discount valid only for low-demand class types is a more efficient lever than a blanket discount. A time-of-day auto-apply discount does the same for quiet hours, and your calendar advertises it for you.
* **Use a promotion, not a pricing rule, for an offer you want members to see.** Pricing rules set your everyday prices silently. A promotion is named on the calendar and the receipt, can be capped, and shows up in promotion analytics.
* **Build trials with auto-apply, not free plans.** A 100% auto-apply discount on a paid plan converts to a real subscription at the next renewal without any admin intervention. A separate "free trial plan" requires a manual migration step to start charging.
* **For one-time intro pricing on a recurring plan, prefer a coded discount over auto-apply.** Auto-apply embeds the discount in the membership and carries it through every renewal; a one-shot intro is cleaner as a code that only applies to the creation transaction.
* **Don't confuse promotions with leads.** [Leads](/members/leads) are sales opportunities tracked in your pipeline under **Members** > **Leads** - a completely separate feature from promotions.

## Related

* [Leads and pipeline](/members/leads) - sales-opportunity tracking on the **Leads** tab of **Members** (it replaced deals).
* [Plans](/sales/plans) - membership plan pricing.
* [Transactions](/sales/transactions) - where voucher redemptions and discount adjustments appear on a member's ledger.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.