Apply discounts in Stripe Checkout by creating a Coupon (percentage or fixed amount), optionally wrapping it in a Promotion Code, and passing it to your Checkout Session via discounts or allow_promotion_codes. Customers see the discount applied on the Stripe-hosted page before paying.
Discounts in Stripe Checkout: Coupons vs Promotion Codes
Stripe has two discount concepts: Coupons and Promotion Codes. A Coupon defines the discount (e.g., 20% off or $5 off). A Promotion Code wraps a Coupon in a customer-facing code string (e.g., SAVE20). You can auto-apply a coupon to a Checkout Session using the discounts array, or let customers enter a promotion code by enabling allow_promotion_codes. Both work for one-time payments and subscriptions.
Prerequisites
- A Stripe account with test API keys
- Node.js 18+ with the stripe npm package installed
- A working Checkout Session endpoint (see 'How to Create a Checkout Session')
Step-by-step guide
Create a percentage-off Coupon
Create a percentage-off Coupon
Create a Coupon that gives a percentage discount. Coupons can be reusable or limited to a certain number of redemptions.
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);23// 20% off coupon4const coupon = await stripe.coupons.create({5 percent_off: 20,6 duration: 'once', // 'once', 'repeating', or 'forever'7 name: '20% Off', // Displayed to customers8 max_redemptions: 100, // Optional: limit total uses9});1011console.log('Coupon ID:', coupon.id); // e.g., 'Z4OV52SU'Expected result: A Coupon object is created. You'll use its ID to apply discounts to Checkout Sessions.
Create a fixed-amount Coupon
Create a fixed-amount Coupon
Create a Coupon that subtracts a specific dollar amount from the total.
1// $5 off coupon2const fixedCoupon = await stripe.coupons.create({3 amount_off: 500, // $5.00 in cents4 currency: 'usd',5 duration: 'once',6 name: '$5 Off Your Order',7});Expected result: A fixed-amount Coupon that deducts $5 from the checkout total.
Auto-apply a coupon to a Checkout Session
Auto-apply a coupon to a Checkout Session
Pass the coupon ID in the discounts array when creating the Checkout Session. The discount is automatically applied — the customer sees the reduced price.
1const session = await stripe.checkout.sessions.create({2 mode: 'payment',3 line_items: [4 {5 price_data: {6 currency: 'usd',7 product_data: { name: 'Premium Plan' },8 unit_amount: 5000, // $50.009 },10 quantity: 1,11 },12 ],13 discounts: [14 { coupon: coupon.id }, // Auto-applies the discount15 ],16 success_url: 'https://yoursite.com/success',17 cancel_url: 'https://yoursite.com/cancel',18});Expected result: The Checkout page shows the original price with a discount line (e.g., '$50.00 - 20% off = $40.00').
Let customers enter a Promotion Code
Let customers enter a Promotion Code
Instead of auto-applying, create a Promotion Code (a customer-facing string) and enable the promotion code field on Checkout. Customers type the code themselves.
1// Create a Promotion Code from a Coupon2const promoCode = await stripe.promotionCodes.create({3 coupon: coupon.id,4 code: 'SAVE20', // Customer-facing code5 max_redemptions: 50, // Optional limit6 active: true,7});89// Enable promotion code entry in Checkout Session10const session = await stripe.checkout.sessions.create({11 mode: 'payment',12 line_items: [{ price: 'price_xxx', quantity: 1 }],13 allow_promotion_codes: true, // Shows promo code input14 success_url: 'https://yoursite.com/success',15 cancel_url: 'https://yoursite.com/cancel',16});Expected result: The Checkout page shows a 'Add promotion code' link. Customers can enter SAVE20 to get 20% off.
Test the discount flow
Test the discount flow
Test in Stripe test mode to verify discounts display correctly and the final charge reflects the discount.
1// Test card: 4242 4242 4242 42422// With 20% off on a $50 item:3// Subtotal: $50.004// Discount: -$10.005// Total: $40.0067// Verify in Dashboard → Payments — the charge should be $40.00Expected result: The Stripe Dashboard shows a payment for the discounted amount with the coupon noted.
Complete working example
1const express = require('express');2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);34const app = express();5app.use(express.json());67// Create a reusable coupon (run once or via admin)8app.post('/create-coupon', async (req, res) => {9 const { percent_off, amount_off, currency, duration, name } = req.body;1011 const params = { duration: duration || 'once', name };12 if (percent_off) params.percent_off = percent_off;13 if (amount_off) {14 params.amount_off = amount_off;15 params.currency = currency || 'usd';16 }1718 const coupon = await stripe.coupons.create(params);19 res.json({ couponId: coupon.id });20});2122// Create a promotion code from a coupon23app.post('/create-promo-code', async (req, res) => {24 const { coupon_id, code } = req.body;25 const promo = await stripe.promotionCodes.create({26 coupon: coupon_id,27 code: code.toUpperCase(),28 active: true,29 });30 res.json({ promoCodeId: promo.id, code: promo.code });31});3233// Checkout with auto-applied discount34app.post('/checkout-with-discount', async (req, res) => {35 const { coupon_id } = req.body;3637 const session = await stripe.checkout.sessions.create({38 mode: 'payment',39 line_items: [{40 price_data: {41 currency: 'usd',42 product_data: { name: 'Premium Widget' },43 unit_amount: 5000,44 },45 quantity: 1,46 }],47 discounts: coupon_id ? [{ coupon: coupon_id }] : [],48 success_url: `${req.headers.origin}/success`,49 cancel_url: `${req.headers.origin}/cancel`,50 });5152 res.json({ url: session.url });53});5455// Checkout with customer promo code entry56app.post('/checkout-with-promo-field', async (req, res) => {57 const session = await stripe.checkout.sessions.create({58 mode: 'payment',59 line_items: [{60 price_data: {61 currency: 'usd',62 product_data: { name: 'Premium Widget' },63 unit_amount: 5000,64 },65 quantity: 1,66 }],67 allow_promotion_codes: true,68 success_url: `${req.headers.origin}/success`,69 cancel_url: `${req.headers.origin}/cancel`,70 });7172 res.json({ url: session.url });73});7475app.listen(4000, () => console.log('Server on port 4000'));Common mistakes when applying discounts in Stripe Checkout
Why it's a problem: Using both discounts and allow_promotion_codes on the same session
How to avoid: Stripe does not allow both. Use discounts to auto-apply a specific coupon, or use allow_promotion_codes to let the customer enter a code.
Why it's a problem: Confusing Coupons with Promotion Codes
How to avoid: A Coupon defines the discount rules (20% off, $5 off). A Promotion Code is a customer-facing code string (SAVE20) linked to a Coupon. Customers enter Promotion Codes, not Coupon IDs.
Why it's a problem: Creating fixed-amount coupons without specifying the currency
How to avoid: Fixed-amount Coupons (amount_off) require a currency field. Percentage Coupons (percent_off) do not.
Why it's a problem: Not setting max_redemptions or expiry on coupons
How to avoid: Without limits, coupons can be used indefinitely. Set max_redemptions and/or redeem_by (Unix timestamp) to control usage.
Best practices
- Use Promotion Codes (SAVE20) for customer-facing discounts and Coupons for system-applied discounts
- Set max_redemptions and redeem_by on coupons to prevent unlimited use
- Use percent_off for percentage discounts and amount_off (in cents) for fixed discounts
- Test discount flows in test mode with card 4242 4242 4242 4242 and verify the charged amount
- For subscriptions, use duration: 'repeating' with duration_in_months to apply discounts over multiple cycles
- Track coupon usage in Dashboard → Products → Coupons to monitor redemption rates
Still stuck?
Copy one of these prompts to get a personalized, step-by-step explanation.
Write Node.js code to create a Stripe Coupon (20% off, one-time) and a Promotion Code (SAVE20). Then create a Checkout Session that allows the customer to enter the promotion code using allow_promotion_codes: true.
Add discount support to my Stripe Checkout. Create: 1) A 20% off coupon. 2) A promotion code SAVE20 linked to it. 3) A checkout endpoint that enables the promotion code input field so customers can enter SAVE20 to get the discount.
Frequently asked questions
Can I apply multiple discounts to one Checkout Session?
No. Stripe Checkout supports only one discount per session. If you need stacked discounts, calculate the combined discount and create a single coupon for it.
Can I create coupons from the Stripe Dashboard?
Yes. Go to Products → Coupons → Create coupon. You can set percentage or fixed amount, duration, and limits without writing any code.
Do discounts work with subscriptions?
Yes. Set duration to 'repeating' with duration_in_months for multi-cycle discounts, or 'forever' for a permanent discount on the subscription.
How do I prevent abuse of promotion codes?
Set max_redemptions to limit total uses, first_time_transaction: true to restrict to new customers, and minimum_amount to require a minimum order. You can also restrict codes to specific customers.
What if I need complex promotional logic?
For advanced discount scenarios — tiered pricing, bundle discounts, or dynamic promotions based on cart contents — RapidDev can help build custom discount logic on top of Stripe's coupon system.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation