Skip to main content
RapidDev - Software Development Agency
stripe-guide

How to apply discounts in Stripe Checkout

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.

What you'll learn

  • How to create Coupons (percentage and fixed amount) via the API
  • How to create Promotion Codes from Coupons for customer-facing codes
  • How to apply discounts to Checkout Sessions automatically or via promotion code entry
  • The difference between Coupons and Promotion Codes in Stripe
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner6 min read15 minutesStripe API v2024-12+, Node.js 18+March 2026RapidDev Engineering Team
TL;DR

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

1

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.

typescript
1const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
2
3// 20% off coupon
4const coupon = await stripe.coupons.create({
5 percent_off: 20,
6 duration: 'once', // 'once', 'repeating', or 'forever'
7 name: '20% Off', // Displayed to customers
8 max_redemptions: 100, // Optional: limit total uses
9});
10
11console.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.

2

Create a fixed-amount Coupon

Create a Coupon that subtracts a specific dollar amount from the total.

typescript
1// $5 off coupon
2const fixedCoupon = await stripe.coupons.create({
3 amount_off: 500, // $5.00 in cents
4 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.

3

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.

typescript
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.00
9 },
10 quantity: 1,
11 },
12 ],
13 discounts: [
14 { coupon: coupon.id }, // Auto-applies the discount
15 ],
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').

4

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.

typescript
1// Create a Promotion Code from a Coupon
2const promoCode = await stripe.promotionCodes.create({
3 coupon: coupon.id,
4 code: 'SAVE20', // Customer-facing code
5 max_redemptions: 50, // Optional limit
6 active: true,
7});
8
9// Enable promotion code entry in Checkout Session
10const 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 input
14 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.

5

Test the discount flow

Test in Stripe test mode to verify discounts display correctly and the final charge reflects the discount.

typescript
1// Test card: 4242 4242 4242 4242
2// With 20% off on a $50 item:
3// Subtotal: $50.00
4// Discount: -$10.00
5// Total: $40.00
6
7// Verify in Dashboard → Payments — the charge should be $40.00

Expected result: The Stripe Dashboard shows a payment for the discounted amount with the coupon noted.

Complete working example

discount-server.js
1const express = require('express');
2const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);
3
4const app = express();
5app.use(express.json());
6
7// 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;
10
11 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 }
17
18 const coupon = await stripe.coupons.create(params);
19 res.json({ couponId: coupon.id });
20});
21
22// Create a promotion code from a coupon
23app.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});
32
33// Checkout with auto-applied discount
34app.post('/checkout-with-discount', async (req, res) => {
35 const { coupon_id } = req.body;
36
37 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 });
51
52 res.json({ url: session.url });
53});
54
55// Checkout with customer promo code entry
56app.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 });
71
72 res.json({ url: session.url });
73});
74
75app.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.

ChatGPT Prompt

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.

Stripe Prompt

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.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.