Skip to content

Stripe Coupons and Promotions — Discounts and Special Offers

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Stripe Coupons and Promotions. We cover key concepts, practical examples, and best practices to help you master this topic.

Stripe coupons and promotion codes let you offer discounts on subscriptions and one-time purchases, with support for percentage and fixed amounts, duration limits, and usage restrictions.

What You'll Learn

By the end of this lesson you will understand how to create coupons, generate promotion codes, apply discounts to subscriptions and invoices, and enforce usage limits.

Why It Matters

Promotions drive customer acquisition and retention. Stripe handles discount application, proration, and expiration automatically, ensuring consistent pricing across your customer base.

Real-World Use

DodaZIP offers a 20% annual discount coupon and first-month-free promotion codes. Stripe applies these automatically during Checkout and handles the billing adjustments.

flowchart LR
    C[Create Coupon] --> PC[Generate Promotion Code]
    PC --> APP[Apply at Checkout]
    APP --> S[Discount Applied]
    S --> R[Recurring Discount]
    R -->|Duration ends| F[Full Price]
    style C fill:#6772e5,color:#fff

Creating Coupons

Coupons define the discount. They can be percentage-based or fixed-amount.

import stripe
import os

stripe.api_key = os.environ.get("STRIPE_SECRET_KEY", "sk_test_placeholder")

def create_percent_coupon(percent, duration="forever", name=None):
    coupon = stripe.Coupon.create(
        percent_off=percent,
        duration=duration,
        name=name or f"{percent}% off",
    )
    return coupon.id

def create_amount_coupon(amount_cents, currency="usd", duration="once"):
    coupon = stripe.Coupon.create(
        amount_off=amount_cents,
        currency=currency,
        duration=duration,
    )
    return coupon.id

stripe.api_key = "sk_test_placeholder"

class MockCoupon:
    id = "coupon_test"

stripe.Coupon.create = lambda **kwargs: MockCoupon()

percent_off = create_percent_coupon(20, "forever", "20% annual discount")
amount_off = create_amount_coupon(1000, "usd", "once")

print(f"Coupons created:")
print(f"  Percent: {percent_off} (20% off forever)")
print(f"  Amount: {amount_off} ($10.00 off once)")

Expected output:

Coupons created:
  Percent: coupon_test (20% off forever)
  Amount: coupon_test ($10.00 off once)

Promotion Codes

Promotion codes are customer-facing codes that customers enter at checkout.

# promotion_codes.py
# Creating promotion codes

def create_promotion_code(coupon_id, code, max_redemptions=None, expires_at=None):
    restrictions = {}
    if max_redemptions:
        restrictions["max_redemptions"] = max_redemptions
    if expires_at:
        restrictions["expires_at"] = expires_at
    
    promo = {
        "id": f"promo_{code.lower()}",
        "code": code,
        "coupon": coupon_id,
        "restrictions": restrictions,
        "active": True
    }
    
    print(f"Promotion code: {code}")
    print(f"  Coupon: {coupon_id}")
    print(f"  Max redemptions: {max_redemptions or 'Unlimited'}")
    print(f"  Active: True")
    return promo

codes = [
    ("SAVE20", "coupon_20percent", 100),
    ("WELCOME10", "coupon_10dollar", 500),
    ("FREEMONTH", "coupon_firstmonth", None),
]

for code, coupon, max_redemptions in codes:
    create_promotion_code(coupon, code, max_redemptions)
    print()

Applying to Subscriptions

Coupons are applied at subscription creation or invoice generation.

# apply_discount.py
# Applying coupons to subscriptions

def apply_coupon(subscription_id, coupon_id):
    print(f"Applying coupon {coupon_id} to subscription {subscription_id}")
    print(f"  -> Coupon applied successfully")
    
    if coupon_id.startswith("coupon_20"):
        print("  -> 20% discount on all future renewals")
    elif coupon_id == "coupon_firstmonth":
        print("  -> 100% off first month only")

def calculate_discounted_price(original_price, coupon):
    if coupon["type"] == "percent":
        discounted = original_price * (1 - coupon["value"] / 100)
    else:
        discounted = max(0, original_price - coupon["value"])
    
    savings = original_price - discounted
    print(f"Original: ${original_price/100:.2f}")
    print(f"Discounted: ${discounted/100:.2f}")
    print(f"You save: ${savings/100:.2f}")
    return discounted

calculate_discounted_price(2999, {"type": "percent", "value": 20})

Common Mistakes

  1. Not setting duration limitations: Forever coupons discount every renewal. Use duration=once or duration=repeating with duration_in_months for limited discounts.

  2. Creating too many promotion codes: Each code has separate tracking. Clean up expired codes regularly.

  3. Not testing coupon stacking: By default only one coupon applies. Configure promotion code stackability if needed.

  4. Forgetting max redemptions: Without limits, a promotion code can be used infinitely. Set max_redemptions for limited offers.

  5. Applying coupons after subscription creation: Coupons applied mid-cycle are prorated. Apply at subscription creation for clean billing.

Practice Questions

  1. What is the difference between a coupon and a promotion code? A coupon defines the discount. A promotion code is a customer-facing code that applies a coupon.

  2. What duration options are available for coupons? once (single billing cycle), repeating (specified number of cycles), forever (all cycles).

  3. How do you limit promotion code usage? Set max_redemptions on the promotion code when creating it.

  4. Can a customer use multiple coupons? By default, no. Only one coupon applies per subscription or invoice.

  5. Challenge: Design a promotion system with referral codes, first-purchase discount, and seasonal promotions with expiration dates.

FAQ

Can I update a coupon after creation?

Coupon parameters are immutable. Deactivate and create a new coupon with updated parameters.

How does a coupon affect trial periods?

Coupons apply after the trial ends. The trial itself is always free.

Can I use coupons with Checkout?

Yes. Checkout accepts promotion codes in the allow_promotion_codes parameter.

What happens when a coupon expires for an existing subscription?

The subscription continues at the full price starting the next billing cycle.

Can I see which customers used a promotion code?

Yes. The promotion code is recorded on the subscription or invoice for reporting.

Mini Project

Create a promotion code endpoint that generates a coupon and promotion code with configurable discount and restrictions.

import json
import random
import string

def lambda_handler(event, context):
    body = json.loads(event.get("body", "{}"))
    discount_percent = body.get("discount_percent", 10)
    duration = body.get("duration", "once")
    max_uses = body.get("max_uses", 100)
    
    coupon_id = f"coupon_{discount_percent}pct"
    code = "".join(random.choices(string.ascii_uppercase + string.digits, k=8))
    
    print(f"Created {discount_percent}% off coupon ({coupon_id})")
    print(f"Promotion code: {code}")
    print(f"Duration: {duration}")
    print(f"Max uses: {max_uses}")
    
    return {
        "statusCode": 201,
        "body": json.dumps({
            "coupon_id": coupon_id,
            "promotion_code": code,
            "discount_percent": discount_percent,
            "duration": duration,
            "max_uses": max_uses
        })
    }

print(json.loads(lambda_handler({"body": json.dumps({"discount_percent": 25, "duration": "repeating", "max_uses": 50})}, None)["body"]))

What's Next

Next: Testing Stripe for test cards and scenarios.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro