How do I define the discount itself?
A currency left unconfigured on an
AMOUNT_OFF coupon is not eligible — an order in that currency is
refused rather than silently charged full price. Configure every currency you sell in.
Duration counts billing cycles, so it only bites on subscriptions; a one-time payment consumes the discount
once either way. ONCE — a single payment only, and a second attempt on the same discount is refused.
REPEATING — N cycles, where you also set Duration in Cycles. FOREVER — every cycle.
What else do I fill in when creating a coupon?
Discount type, discount value and duration are immutable after creation — the page warns you before you
submit, and afterwards only Name and Metadata are editable. Deactivate stops further redemptions and
is reversible; Archive is irreversible and also deactivates the coupon’s promotion codes. Neither touches
discounts already applied. The list shows a lifecycle tag rather than a raw status: archived wins, then expired
(past
redeemBy), then the coupon’s own state.
How do I issue promotion codes?
Batch creation is a four-step wizard — pick the coupon, set prefix and quantity, set restrictions, then a
preview returning sample codes and an estimated generation time before you commit. Generated codes are
permanent, so plan the prefix and quantity first. The batch runs asynchronously: Batch Tasks lists Task ID,
coupon, status (
PENDING → PROCESSING → SUCCESS / FAILED), success count and creation time, and links
through to the codes a task produced. A code-level expiry cannot extend the coupon — the coupon’s own redeemBy
is still checked separately, so the earlier of the two ends redemption.
Why was a code refused at checkout?
Eligibility is decided before the amount is calculated, roughly in this order:- Coupons are disabled on your account, or no coupon configuration exists yet.
- The coupon or the code is inactive, expired, or has exhausted its redemption stock; or the code does not belong to the coupon passed in the same request.
- The order amount is below the code’s Minimum Amount for that currency, or
AMOUNT_OFFhas no amount configured for the order currency. - A per-customer limit, a daily limit or First Time Only applies, but the request carried no customer identifier — the discount is refused rather than applied unrestricted.
- First Time Only and the customer already has a completed redemption — scoped to your account as a whole, not to this one coupon.
- A
ONCEcoupon was already used, or aREPEATINGcoupon has used up its cycles.
Where do I see who redeemed what?
The coupon detail page has Overview, Promotion Codes and Redemption History tabs. Each redemption row carries Record ID, promotion code, customer, source type and source ID, Original / Discount / Final amount in the order currency, status and creation time. Filter by customer, source ID, status and date range, then export the filtered view. Status runsCREATED (reserved, not yet final) → COMPLETED (confirmed — the only
state analytics counts), or VOIDED (the payment never completed, reservation released) / REVERSED (rolled
back after a refund).
How is Discount Analytics calculated?
Three caveats decide whether the numbers match your own. It counts completed redemptions only, soCREATED,
VOIDED and REVERSED are excluded. Amounts are summed across currencies with no conversion, which is why
the cards and the performance table show bare numbers without a currency symbol — use the redemption export for
per-currency totals. And Redemption Rate = completed redemptions ÷ the summed Max Redemptions of the coupons
in scope, so coupons with no cap contribute 0 to the denominator.
Default range is the last 30 days. The trend chart buckets by each redemption’s confirmation time in your
Portal time zone, and the Daily / Weekly / Monthly toggle re-buckets the same data. Coupon Performance splits
the period per coupon: Total Codes, Redemptions, Total Discount, Redemption Rate, Average Order Value.
What do the account-level coupon settings do?
What happens to a discount on refund, and during a subscription trial?
Under the Full Reversal strategy, a full refund reverses the redemption — the record becomesREVERSED
and the slot returns to both the coupon and the code. A partial refund does not reverse it: the record
stays COMPLETED and the slot stays consumed. A payment that never completed releases the reservation as
VOIDED instead. Reversal returns only what was actually consumed, so a cycle that never received a real
discount cannot push a counter negative.
A zero-amount trial period occupies that period’s redemption slot on the coupon and code, but does not
burn the discount’s own lifecycle count. A ONCE coupon on a subscription with a free trial therefore still has
its single real discount available for the first paid cycle. Outside subscriptions, a zero-amount order with no
discount actually applied consumes nothing.
How do I apply a discount through the API?
Order create carries apromotionInfo object with two mutually exclusive fields, each up to 64 characters.
promotionInfo.promotionCode is used by you or by the Waffo-hosted checkout page — the checkout discount input
accepts a promotion code only, so a customer can never type a coupon ID. promotionInfo.couponId is yours
alone, at order create, to apply a specific coupon with no code involved. Pass one or the other, never both; if
a code and a coupon ID both arrive, the code must belong to that coupon. Field-level rules for order create and
the checkout page’s own behaviour are covered in the order-create field guide and the checkout page docs.
What can I export from the Marketing pages?
Everything the Marketing pages manage is a Portal feature — create, edit, deactivate and archive coupons; create single codes and code batches; browse redemptions and analytics — and there is no API-key-signed integration endpoint for any of it. The only API touchpoint ispromotionInfo on order create, above.
Four lists have an Export button: Coupons, Promotion Codes, Redemption History and Discount Analytics. Each
export runs as a task and hands you a CSV named <type>-<task-id>.csv — prefix coupon, promotion-code,
promotion-record or promotion-analytics. An export honours the filters on screen and covers up to 10,000
rows. Timestamps in lists and exports render in your Portal time zone; the Portal sends its offset with the
request.
Numbers not adding up? Contact support with the coupon ID, the promotion code, or the redemption Record ID.