Coupons and promotions
Share this article
Overview
Coupons are discount codes for your outfitter account. Each code can take either a percentage off or a fixed dollar amount off (USD), with an optional expiration date. New codes are created as one-time-use duration coupons in the dashboard (duration: once in the product implementation)—other duration modes are not exposed in the create form here.
Codes belong to the outfitter, not to an individual listing. When you send a quote (booking invite) or create a booking in the dashboard, you pick a listing first; the coupon picker then loads every coupon for that listing’s outfitter. The GraphQL API does not accept a listing ID when creating a coupon, so this dashboard does not offer per-listing coupon restrictions. If you need a discount to apply only to certain trips, use separate codes or campaigns operationally unless another Mallard Bay surface adds listing rules.
You can manage coupons on the dedicated Coupons page (/coupons) and from My Outfitter → Payments & Financials (the coupons block uses the same add coupon modal).
Not verified from this codebase: how guests enter codes on your public website or booking widget, whether max_redemptions or name are set only on the server, and where reports show coupon usage. The data model includes max_redemptions and name, and the coupons table can display them, but the create form only collects custom code, discount type/amount, and optional expiration.
Prerequisites
- Coupons on your plan — The Coupons area checks the Coupons feature (
FeatureKey.Coupons). If it is off or your account has hit its coupon limit, opening Create Coupon shows upgrade or limit messaging instead of the form (FeatureUpsellModal). - Outfitter context — Codes are created for the currently selected outfitter (the modal title is Add coupon for … plus the outfitter name). Users without a selected outfitter may see the all coupons query instead of a single outfitter’s list (implementation switches between
couponsByOutfitterandallCoupons). - Permissions — In quote and booking flows, New coupon is hidden when dashboard action permissions disallow it (
shouldShowActions); other entry points may still be available depending on role.
Step-by-step: Create and manage coupons (`/coupons`)
- Open Coupons in the dashboard (
/coupons). The page is wrapped in the same Coupons feature gate as creation. - Select Create Coupon in the page header. If you see an upgrade or limit dialog, your plan or coupon count is blocking new codes.
- In the modal, complete the form:
- Custom code — Required (for example a guest-facing code like
WINTER20). - Discount type — Percent off or Amount off.
- Discount amount — Required; must be greater than zero. For dollar discounts the value is stored as a money amount with USD currency on create.
- Expiration date — Optional. After this timestamp, the code is treated as expired in selectors (
redeem_bycompared to the current time).
- Custom code — Required (for example a guest-facing code like
- Submit. The app creates the coupon and refreshes coupon queries.
- Use the table search to filter by coupon code (search matches
custom_code, case-insensitive). - Review columns where applicable: name, code (with copy control), discount amount, limit (shows
max_redemptionswhen present), expiration, and outfitter (helpful in multi-outfitter contexts). - To remove a code, use delete on the row and confirm. Deletion is permanent once confirmed (confirmation copy comes from
COUPON_CONFIRMATIONstrings).
Step-by-step: Coupons from **My Outfitter**
- Go to My Outfitter and open Payments & Financials.
- Find the Coupons section.
- Use Add coupon from the section menu (same modal as elsewhere; Add coupon can appear locked if the Coupons feature is disabled).
- Existing coupons list code, name (or “No name entered”), optional expiration (
M/d/yyyy), clipboard copy on the code, and delete.
Step-by-step: Apply a coupon on a **quote (booking invite)**
- Start or edit a quote flow and reach the step labeled Payments (this step hosts coupon selection).
- Pick a coupon card, or tap New coupon (when allowed) to create one inline; new coupons are applied via the same picker after creation.
- Use search and Show expired / Hide expired if you have many codes; expired coupons are disabled with an “expired” tooltip.
- Optionally use Editable at checkout for the coupon field so guests can change it when they complete checkout—unless the invite is invoice-style, in which case those toggles are hidden and the backend drives editability.
Step-by-step: Apply a coupon when **creating a booking** (dashboard)
- In the create booking flow, open the Payment step (combined Payment information and Coupon UI).
- Choose a coupon from the grid; options come from
couponsByOutfitterfor the selected listing’s outfitter. - When the flow is backed by a quote, changing the coupon triggers
applyQuoteCoupon/removeQuoteCoupon(the mutation argument is namedcouponCodebut the dashboard passes the coupon’s internal id—guests still use the custom code). - Finish the flow as usual. Coupons interact with quoted totals and payments for that reservation path.
Implementation note for operators: Coupon changes after a quote exists are applied via those quote mutations. If a selection does not seem to affect totals, confirm the quote/pricing has finished loading and try selecting the coupon again once the quote is present.
Common pitfalls
- Plan or limit — Create Coupon may open upsell/limit messaging instead of the form even when the Coupons section is visible elsewhere.
- Expired codes — They appear disabled in pickers; use show expired only if you need to see old codes.
- No per-listing targeting in this UI — All outfitter coupons can surface for any of that outfitter’s listings in these flows unless enforced outside this dashboard.
- Display name and redemption limit — The create dialog does not ask for a name or max redemptions; cards may show a blank title where
nameis empty, and limits only appear if the backend populated them. - Inline “New coupon” — Hidden without action permissions even if coupons are enabled.
Related workflows
- Quotes and booking invites — Optional coupon on the Payments step; editable at checkout controls guest flexibility for the coupon field (non-invoice invites).
- Bookings and payments — Coupon sits on the Payment step next to payment details; quote-backed bookings sync coupon changes through quote mutations.
- Listings — Listing choice determines which outfitter’s coupon list loads, linking trips to your codes in practice while codes remain outfitter-owned.