Create a compatible Offer
A Promo Code can reference any Offer: orderedpercentage, amount_off, or fixed_price phases where only the last phase may be open-ended.
fixed_price phase of 0, Free cycles in the dashboard, makes a code that gives free billing cycles. Checkout saves the card and settles the invoice at $0 without a charge.
Create the code
- the customer-facing code;
- optional plan and billing-interval restrictions;
- the redemption limit;
- expiration and active state;
firstPurchaseOnly, which limits the code to a customer’s first purchase. Defaultfalse.
active or past_due subscription on a paid plan. A customer in a trial qualifies.
Updating the Offer changes future redemptions of codes that reference it. Each completed checkout counts one redemption and keeps an immutable Offer Application with the phases accepted at that checkout. Editing the Offer does not change earlier redemptions or their renewals.
Clients pinned before 2026-07-24 receive only the first phase in the legacy Promo Code discount fields when that phase is percentage or amount_off. Codes starting with fixed_price cannot be represented and are absent from those older Promo Code endpoints. Use the current Offer API to inspect the complete sequence.
Checkout behavior
The customer enters the code during checkout. Commet validates the code, resolves the referenced Offer in the checkout currency, and records an Offer Application with sourcepromo_code.
When the price has a trial that requires a payment method, the customer can enter the code in the trial checkout. The trial starts without a charge and the discount starts with the first invoice after it. One redemption is recorded when the checkout completes. Renewals do not count as new redemptions.
If an eligible automatic Introductory Offer applies, the code is rejected with intro_offer_active. A Promo Code also cannot be combined with an explicit offerId.
Apply a code on a plan change
changePlan and previewChange accept promoCode for immediate changes. The preview quotes what the change charges.
offer_not_applicable.
Rejection reasons
A rejected code returns400 validation_error with param: "promoCode" and the reason in details.reason:
not_found: no code with that text exists.inactive: the code is deactivated.expired: the expiration date passed.max_redemptions_reached: the redemption limit was reached.first_purchase_only: the customer already paid or has a paid subscription.already_redeemed: the customer already redeemed the code.plan_not_eligible: the code is restricted to other plans.billing_interval_not_eligible: the code is restricted to another billing interval.intro_offer_active: an Introductory Offer applies.
Codes managed by an integration
Codes created by an integration, such as Dub, havemanagedBy set. Changing their restrictions returns 409 managed_by_integration; activating and deactivating them still works.