The two layers
A Coupon is the discount rule — how much comes off, which items it applies to, how many periods it lasts, and the total redemption cap. A Promotion Code is the string the customer types — or one you attach in advance. EverywherepromotionCode appears below, it is the customer-facing code string such as WELCOME20 — never a couponId or promotionCodeId.
Creating them
One call can create a Coupon together with its codes:discountTypeispercentageorfixed_amount. A percentage must be above 0 and no more than 100- Fixed amounts use
fixedAmountskeyed by currency, still in the major currency unit (19.99 is19.99) applyTypeisnone,product, orprice. The last two require the matching IDsdurationTypeisonce,repeating, orforever- A promotion code is 1 to 32 letters or digits. Omit
codeand the platform can generate one - Validity uses 13-digit Unix millisecond timestamps. A code’s end time never exceeds its Coupon’s end time
POST /promotion-code/{couponId}. Full fields are in Create coupon.
Applying them per integration path
The full Elements event code lives in Elements — it is not duplicated here.
Validation rules
These catch people out most often: Inline items only work with unrestricted Coupons. Items built frompriceDataList have no productId or priceId, so they can only use a Coupon with applyType: none. A Coupon restricted to a product or price fails validation.
A fixed-amount Coupon must cover the order currency. If the order’s original currency has no amount in fixedAmounts, the Coupon does not apply. A discount larger than the order reduces it to 0 rather than going negative.
Percentage discounts round down to the currency’s maximum decimal places. Do not recompute on the frontend — display the amount returned by the Session, the preview endpoint, or the Elements amount-change event.
firstOrderOnly is judged by whether that Customer has a successful Order. Not by browser, not by email text, and not by visits to your own pages.
minimumSpend is checked against the order’s original amount and currency. If that currency is not configured, the condition is not met.
Errors surface at different moments. The hidden-code mode fails when the Session is created. The visible-input mode shows the error when the customer clicks apply.
You do not redeem codes yourself. The system reserves a redemption when the order is created, confirms it on successful payment, and releases it on failure.
How long a subscription discount lasts
Discounts produce no webhooks of their own
Discounts do not emit a separate “payment succeeded” event. Confirming money still works the same way:- One-time payments: read the Order and Session result
- Subscriptions: read the Subscription and Invoice result
couponId, promotionCode, the original price, the discount, and the amount paid locally for display and reconciliation. But do not recalculate the discount yourself after a webhook arrives — the amounts Clink returns are authoritative.
Two things to verify yourself
Next
Subscriptions
Recurring prices, subscription status, and renewals.
Coupon concepts
Resource definitions and dashboard management.