# How to apply discounts in Stripe Checkout

- Tool: Stripe
- Difficulty: Beginner
- Time required: 15 minutes
- Compatibility: Stripe API v2024-12+, Node.js 18+
- Last updated: March 2026

## 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.

## Before you start

- 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.

```
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

// 20% off coupon
const coupon = await stripe.coupons.create({
  percent_off: 20,
  duration: 'once',       // 'once', 'repeating', or 'forever'
  name: '20% Off',        // Displayed to customers
  max_redemptions: 100,   // Optional: limit total uses
});

console.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.

```
// $5 off coupon
const fixedCoupon = await stripe.coupons.create({
  amount_off: 500,        // $5.00 in cents
  currency: 'usd',
  duration: 'once',
  name: '$5 Off Your Order',
});
```

**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.

```
const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: [
    {
      price_data: {
        currency: 'usd',
        product_data: { name: 'Premium Plan' },
        unit_amount: 5000, // $50.00
      },
      quantity: 1,
    },
  ],
  discounts: [
    { coupon: coupon.id }, // Auto-applies the discount
  ],
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
});
```

**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.

```
// Create a Promotion Code from a Coupon
const promoCode = await stripe.promotionCodes.create({
  coupon: coupon.id,
  code: 'SAVE20',         // Customer-facing code
  max_redemptions: 50,    // Optional limit
  active: true,
});

// Enable promotion code entry in Checkout Session
const session = await stripe.checkout.sessions.create({
  mode: 'payment',
  line_items: [{ price: 'price_xxx', quantity: 1 }],
  allow_promotion_codes: true,  // Shows promo code input
  success_url: 'https://yoursite.com/success',
  cancel_url: 'https://yoursite.com/cancel',
});
```

**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.

```
// Test card: 4242 4242 4242 4242
// With 20% off on a $50 item:
// Subtotal: $50.00
// Discount: -$10.00
// Total: $40.00

// 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 code example

File: `discount-server.js`

```javascript
const express = require('express');
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY);

const app = express();
app.use(express.json());

// Create a reusable coupon (run once or via admin)
app.post('/create-coupon', async (req, res) => {
  const { percent_off, amount_off, currency, duration, name } = req.body;

  const params = { duration: duration || 'once', name };
  if (percent_off) params.percent_off = percent_off;
  if (amount_off) {
    params.amount_off = amount_off;
    params.currency = currency || 'usd';
  }

  const coupon = await stripe.coupons.create(params);
  res.json({ couponId: coupon.id });
});

// Create a promotion code from a coupon
app.post('/create-promo-code', async (req, res) => {
  const { coupon_id, code } = req.body;
  const promo = await stripe.promotionCodes.create({
    coupon: coupon_id,
    code: code.toUpperCase(),
    active: true,
  });
  res.json({ promoCodeId: promo.id, code: promo.code });
});

// Checkout with auto-applied discount
app.post('/checkout-with-discount', async (req, res) => {
  const { coupon_id } = req.body;

  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: [{
      price_data: {
        currency: 'usd',
        product_data: { name: 'Premium Widget' },
        unit_amount: 5000,
      },
      quantity: 1,
    }],
    discounts: coupon_id ? [{ coupon: coupon_id }] : [],
    success_url: `${req.headers.origin}/success`,
    cancel_url: `${req.headers.origin}/cancel`,
  });

  res.json({ url: session.url });
});

// Checkout with customer promo code entry
app.post('/checkout-with-promo-field', async (req, res) => {
  const session = await stripe.checkout.sessions.create({
    mode: 'payment',
    line_items: [{
      price_data: {
        currency: 'usd',
        product_data: { name: 'Premium Widget' },
        unit_amount: 5000,
      },
      quantity: 1,
    }],
    allow_promotion_codes: true,
    success_url: `${req.headers.origin}/success`,
    cancel_url: `${req.headers.origin}/cancel`,
  });

  res.json({ url: session.url });
});

app.listen(4000, () => console.log('Server on port 4000'));
```

## Common mistakes

- **Using both discounts and allow_promotion_codes on the same session** — undefined Fix: 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.
- **Confusing Coupons with Promotion Codes** — undefined Fix: 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.
- **Creating fixed-amount coupons without specifying the currency** — undefined Fix: Fixed-amount Coupons (amount_off) require a currency field. Percentage Coupons (percent_off) do not.
- **Not setting max_redemptions or expiry on coupons** — undefined Fix: 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

## 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.

---

Source: https://www.rapidevelopers.com/stripe-guide/how-to-apply-discounts-in-stripe-checkout
© RapidDev — https://www.rapidevelopers.com/stripe-guide/how-to-apply-discounts-in-stripe-checkout
