Learn how to create, manage, and apply coupon codes in Stripe API with this step-by-step tutorial covering setup, code examples, promotion codes, and best practices.
Book a call with an Expert
Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.
How to Create Coupon Codes in Stripe API: A Comprehensive Tutorial
Step 1: Set Up Your Stripe Account
Before you can create coupon codes, you need to have a Stripe account and set up your development environment:
For Node.js, install the Stripe package using npm:
npm install stripe
For PHP:
composer require stripe/stripe-php
For Python:
pip install stripe
Step 2: Initialize the Stripe Client
Before creating coupons, initialize the Stripe client with your secret key:
Node.js:
const stripe = require('stripe')('sk_test_your_secret_key');
// For async/await usage
async function createCoupon() {
// We'll add code here in the next steps
}
PHP:
\Stripe\Stripe::setApiKey('sk_test_your_secret_key');
Python:
import stripe
stripe.api_key = 'sk_test_your_secret\_key'
Step 3: Create a Basic Percentage-Off Coupon
Let's create a simple coupon that gives customers a percentage discount:
Node.js:
async function createPercentageCoupon() {
try {
const coupon = await stripe.coupons.create({
percent\_off: 20,
duration: 'once',
id: 'SAVE20', // Optional custom ID for the coupon code
});
console.log('Coupon created successfully:');
console.log(coupon);
return coupon;
} catch (error) {
console.error('Error creating coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::create([
'percent\_off' => 20,
'duration' => 'once',
'id' => 'SAVE20', // Optional custom ID for the coupon code
]);
echo 'Coupon created successfully: ' . $coupon->id;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating coupon: ' . $e->getMessage();
}
Python:
try:
coupon = stripe.Coupon.create(
percent\_off=20,
duration='once',
id='SAVE20', # Optional custom ID for the coupon code
)
print('Coupon created successfully:')
print(coupon)
except stripe.error.StripeError as e:
print('Error creating coupon:', e)
Step 4: Create a Fixed-Amount Coupon
To create a coupon with a fixed amount discount:
Node.js:
async function createFixedAmountCoupon() {
try {
const coupon = await stripe.coupons.create({
amount\_off: 1000, // Amount in cents (10 USD)
currency: 'usd',
duration: 'once',
id: 'SAVE10USD',
});
console.log('Fixed amount coupon created:');
console.log(coupon);
return coupon;
} catch (error) {
console.error('Error creating fixed amount coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::create([
'amount\_off' => 1000, // Amount in cents (10 USD)
'currency' => 'usd',
'duration' => 'once',
'id' => 'SAVE10USD',
]);
echo 'Fixed amount coupon created: ' . $coupon->id;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating fixed amount coupon: ' . $e->getMessage();
}
Python:
try:
coupon = stripe.Coupon.create(
amount\_off=1000, # Amount in cents (10 USD)
currency='usd',
duration='once',
id='SAVE10USD',
)
print('Fixed amount coupon created:')
print(coupon)
except stripe.error.StripeError as e:
print('Error creating fixed amount coupon:', e)
Step 5: Create a Coupon with Duration and Redemption Limits
You can set various parameters for coupons, such as duration and redemption limits:
Node.js:
async function createAdvancedCoupon() {
try {
const coupon = await stripe.coupons.create({
percent\_off: 25,
duration: 'repeating',
duration_in_months: 3,
max\_redemptions: 50,
redeem\_by: Math.floor(Date.now() / 1000) + (30 _ 24 _ 60 \* 60), // Valid for 30 days
id: 'SUMMER25',
});
console.log('Advanced coupon created:');
console.log(coupon);
return coupon;
} catch (error) {
console.error('Error creating advanced coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::create([
'percent\_off' => 25,
'duration' => 'repeating',
'duration_in_months' => 3,
'max\_redemptions' => 50,
'redeem\_by' => time() + (30 _ 24 _ 60 \* 60), // Valid for 30 days
'id' => 'SUMMER25',
]);
echo 'Advanced coupon created: ' . $coupon->id;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating advanced coupon: ' . $e->getMessage();
}
Python:
import time
try:
coupon = stripe.Coupon.create(
percent\_off=25,
duration='repeating',
duration_in_months=3,
max\_redemptions=50,
redeem\_by=int(time.time()) + (30 _ 24 _ 60 \* 60), # Valid for 30 days
id='SUMMER25',
)
print('Advanced coupon created:')
print(coupon)
except stripe.error.StripeError as e:
print('Error creating advanced coupon:', e)
Step 6: Create a Promotion Code for an Existing Coupon
Stripe allows you to create multiple promotion codes for a single coupon. This is useful when you want to track different marketing campaigns:
Node.js:
async function createPromotionCode(couponId) {
try {
const promotionCode = await stripe.promotionCodes.create({
coupon: couponId,
code: 'WELCOME15', // Custom code
max\_redemptions: 100,
expires\_at: Math.floor(Date.now() / 1000) + (90 _ 24 _ 60 \* 60), // 90 days
metadata: {
campaign: 'welcome\_email',
source: 'newsletter'
}
});
console.log('Promotion code created:');
console.log(promotionCode);
return promotionCode;
} catch (error) {
console.error('Error creating promotion code:', error);
throw error;
}
}
PHP:
try {
$promotionCode = \Stripe\PromotionCode::create([
'coupon' => 'SAVE20',
'code' => 'WELCOME15', // Custom code
'max\_redemptions' => 100,
'expires\_at' => time() + (90 _ 24 _ 60 \* 60), // 90 days
'metadata' => [
'campaign' => 'welcome\_email',
'source' => 'newsletter'
]
]);
echo 'Promotion code created: ' . $promotionCode->code;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating promotion code: ' . $e->getMessage();
}
Python:
import time
try:
promotion\_code = stripe.PromotionCode.create(
coupon='SAVE20',
code='WELCOME15', # Custom code
max\_redemptions=100,
expires\_at=int(time.time()) + (90 _ 24 _ 60 \* 60), # 90 days
metadata={
'campaign': 'welcome\_email',
'source': 'newsletter'
}
)
print('Promotion code created:')
print(promotion\_code)
except stripe.error.StripeError as e:
print('Error creating promotion code:', e)
Step 7: List Available Coupons
To retrieve all coupons or filter them based on certain criteria:
Node.js:
async function listCoupons() {
try {
const coupons = await stripe.coupons.list({
limit: 10,
});
console.log('Available coupons:');
coupons.data.forEach(coupon => {
console.log(`${coupon.id}: ${coupon.percent_off ? coupon.percent_off + '%' : '$' + (coupon.amount_off / 100)}`);
});
return coupons;
} catch (error) {
console.error('Error listing coupons:', error);
throw error;
}
}
PHP:
try {
$coupons = \Stripe\Coupon::all(['limit' => 10]);
echo "Available coupons:\n";
foreach ($coupons as $coupon) {
echo $coupon->id . ': ' .
($coupon->percent_off ? $coupon->percent_off . '%' : '$' . ($coupon->amount\_off / 100)) . "\n";
}
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error listing coupons: ' . $e->getMessage();
}
Python:
try:
coupons = stripe.Coupon.list(limit=10)
print('Available coupons:')
for coupon in coupons.data:
discount = f"{coupon.percent_off}%" if coupon.percent_off else f"${coupon.amount\_off / 100}"
print(f"{coupon.id}: {discount}")
except stripe.error.StripeError as e:
print('Error listing coupons:', e)
Step 8: Retrieve a Specific Coupon
To get details of a specific coupon:
Node.js:
async function retrieveCoupon(couponId) {
try {
const coupon = await stripe.coupons.retrieve(couponId);
console.log('Coupon details:');
console.log(coupon);
return coupon;
} catch (error) {
console.error('Error retrieving coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::retrieve('SAVE20');
echo 'Coupon details:';
print\_r($coupon);
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error retrieving coupon: ' . $e->getMessage();
}
Python:
try:
coupon = stripe.Coupon.retrieve('SAVE20')
print('Coupon details:')
print(coupon)
except stripe.error.StripeError as e:
print('Error retrieving coupon:', e)
Step 9: Update a Promotion Code
You can update certain properties of a promotion code:
Node.js:
async function updatePromotionCode(promotionCodeId) {
try {
const promotionCode = await stripe.promotionCodes.update(
promotionCodeId,
{
active: false, // Deactivate the promotion code
metadata: {
updated\_by: 'admin',
reason: 'campaign ended'
}
}
);
console.log('Promotion code updated:');
console.log(promotionCode);
return promotionCode;
} catch (error) {
console.error('Error updating promotion code:', error);
throw error;
}
}
PHP:
try {
$promotionCode = \Stripe\PromotionCode::update(
'promo\_1234567890',
[
'active' => false, // Deactivate the promotion code
'metadata' => [
'updated\_by' => 'admin',
'reason' => 'campaign ended'
]
]
);
echo 'Promotion code updated:';
print\_r($promotionCode);
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error updating promotion code: ' . $e->getMessage();
}
Python:
try:
promotion\_code = stripe.PromotionCode.modify(
'promo\_1234567890',
active=False, # Deactivate the promotion code
metadata={
'updated\_by': 'admin',
'reason': 'campaign ended'
}
)
print('Promotion code updated:')
print(promotion\_code)
except stripe.error.StripeError as e:
print('Error updating promotion code:', e)
Step 10: Delete a Coupon
To delete a coupon when it's no longer needed:
Node.js:
async function deleteCoupon(couponId) {
try {
const deleted = await stripe.coupons.del(couponId);
console.log('Coupon deleted:', deleted.id);
return deleted;
} catch (error) {
console.error('Error deleting coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::retrieve('SAVE20');
$deleted = $coupon->delete();
echo 'Coupon deleted: ' . ($deleted->deleted ? 'Yes' : 'No');
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error deleting coupon: ' . $e->getMessage();
}
Python:
try:
deleted = stripe.Coupon.delete('SAVE20')
print('Coupon deleted:', deleted.get('id'))
except stripe.error.StripeError as e:
print('Error deleting coupon:', e)
Step 11: Apply a Coupon to a Subscription
When creating a subscription, you can apply a coupon:
Node.js:
async function createSubscriptionWithCoupon(customerId, priceId, couponId) {
try {
const subscription = await stripe.subscriptions.create({
customer: customerId,
items: [
{ price: priceId },
],
coupon: couponId,
});
console.log('Subscription created with coupon:');
console.log(subscription);
return subscription;
} catch (error) {
console.error('Error creating subscription with coupon:', error);
throw error;
}
}
PHP:
try {
$subscription = \Stripe\Subscription::create([
'customer' => 'cus\_123456789',
'items' => [
['price' => 'price\_123456789'],
],
'coupon' => 'SAVE20',
]);
echo 'Subscription created with coupon:';
print\_r($subscription);
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating subscription with coupon: ' . $e->getMessage();
}
Python:
try:
subscription = stripe.Subscription.create(
customer='cus\_123456789',
items=[
{'price': 'price\_123456789'},
],
coupon='SAVE20',
)
print('Subscription created with coupon:')
print(subscription)
except stripe.error.StripeError as e:
print('Error creating subscription with coupon:', e)
Step 12: Create a Checkout Session with a Coupon
To allow customers to apply coupons during checkout:
Node.js:
async function createCheckoutWithCoupon(priceId) {
try {
const session = await stripe.checkout.sessions.create({
payment_method_types: ['card'],
line\_items: [
{
price: priceId,
quantity: 1,
},
],
mode: 'payment',
allow_promotion_codes: true, // Allow customers to enter promotion codes
success_url: 'https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url: 'https://yourwebsite.com/cancel',
});
console.log('Checkout session created:');
console.log(session);
return session;
} catch (error) {
console.error('Error creating checkout session:', error);
throw error;
}
}
PHP:
try {
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line\_items' => [[
'price' => 'price\_123456789',
'quantity' => 1,
]],
'mode' => 'payment',
'allow_promotion_codes' => true, // Allow customers to enter promotion codes
'success_url' => 'https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
'cancel\_url' => 'https://yourwebsite.com/cancel',
]);
echo 'Checkout session created: ' . $session->id;
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error creating checkout session: ' . $e->getMessage();
}
Python:
try:
session = stripe.checkout.Session.create(
payment_method_types=['card'],
line\_items=[{
'price': 'price\_123456789',
'quantity': 1,
}],
mode='payment',
allow_promotion_codes=True, # Allow customers to enter promotion codes
success_url='https://yourwebsite.com/success?session_id={CHECKOUT_SESSION_ID}',
cancel\_url='https://yourwebsite.com/cancel',
)
print('Checkout session created:')
print(session)
except stripe.error.StripeError as e:
print('Error creating checkout session:', e)
Step 13: Validate Coupon Redemption
When a customer applies a coupon, you might want to validate it before processing the payment:
Node.js:
async function validateCoupon(couponId) {
try {
const coupon = await stripe.coupons.retrieve(couponId);
const now = Math.floor(Date.now() / 1000);
const isValid = coupon.valid &&
(!coupon.redeem_by || coupon.redeem_by > now) &&
(!coupon.max_redemptions || coupon.times_redeemed < coupon.max\_redemptions);
if (isValid) {
console.log('Coupon is valid and can be applied');
} else {
console.log('Coupon is invalid or expired');
}
return { coupon, isValid };
} catch (error) {
console.error('Error validating coupon:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::retrieve('SAVE20');
$now = time();
$isValid = $coupon->valid &&
(!$coupon->redeem_by || $coupon->redeem_by > $now) &&
(!$coupon->max_redemptions || $coupon->times_redeemed < $coupon->max\_redemptions);
if ($isValid) {
echo 'Coupon is valid and can be applied';
} else {
echo 'Coupon is invalid or expired';
}
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error validating coupon: ' . $e->getMessage();
}
Python:
import time
try:
coupon = stripe.Coupon.retrieve('SAVE20')
now = int(time.time())
is\_valid = (coupon.valid and
(not coupon.redeem_by or coupon.redeem_by > now) and
(not coupon.max_redemptions or coupon.times_redeemed < coupon.max\_redemptions))
if is\_valid:
print('Coupon is valid and can be applied')
else:
print('Coupon is invalid or expired')
except stripe.error.StripeError as e:
print('Error validating coupon:', e)
Step 14: Track Coupon Usage and Analytics
To track how often coupons are being used, you can query the coupons and their usage statistics:
Node.js:
async function getCouponUsageStats(couponId) {
try {
const coupon = await stripe.coupons.retrieve(couponId);
const stats = {
id: coupon.id,
times_redeemed: coupon.times_redeemed,
max_redemptions: coupon.max_redemptions,
percent_used: coupon.max_redemptions
? (coupon.times_redeemed / coupon.max_redemptions) \* 100
: 'unlimited',
valid: coupon.valid,
created: new Date(coupon.created \* 1000).toLocaleDateString(),
};
console.log('Coupon usage statistics:');
console.log(stats);
return stats;
} catch (error) {
console.error('Error retrieving coupon usage stats:', error);
throw error;
}
}
PHP:
try {
$coupon = \Stripe\Coupon::retrieve('SAVE20');
$stats = [
'id' => $coupon->id,
'times_redeemed' => $coupon->times_redeemed,
'max_redemptions' => $coupon->max_redemptions,
'percent_used' => $coupon->max_redemptions
? ($coupon->times_redeemed / $coupon->max_redemptions) \* 100
: 'unlimited',
'valid' => $coupon->valid,
'created' => date('Y-m-d', $coupon->created),
];
echo "Coupon usage statistics:\n";
print\_r($stats);
} catch (\Stripe\Exception\ApiErrorException $e) {
echo 'Error retrieving coupon usage stats: ' . $e->getMessage();
}
Python:
from datetime import datetime
try:
coupon = stripe.Coupon.retrieve('SAVE20')
stats = {
'id': coupon.id,
'times_redeemed': coupon.times_redeemed,
'max_redemptions': coupon.max_redemptions,
'percent_used': (coupon.times_redeemed / coupon.max\_redemptions) \* 100
if coupon.max\_redemptions else 'unlimited',
'valid': coupon.valid,
'created': datetime.fromtimestamp(coupon.created).strftime('%Y-%m-%d'),
}
print('Coupon usage statistics:')
for key, value in stats.items():
print(f"{key}: {value}")
except stripe.error.StripeError as e:
print('Error retrieving coupon usage stats:', e)
Step 15: Implementing a Complete Coupon Management System
Here's a complete example showing how to create an Express.js API endpoint for coupon management:
const express = require('express');
const bodyParser = require('body-parser');
const stripe = require('stripe')('sk_test_your_secret_key');
const app = express();
app.use(bodyParser.json());
// Create a new coupon
app.post('/api/coupons', async (req, res) => {
try {
const {
id,
percent\_off,
amount\_off,
currency,
duration,
duration_in_months,
max\_redemptions,
redeem\_by,
} = req.body;
const couponParams = {
duration,
id,
};
// Add optional parameters if they exist
if (percent_off) couponParams.percent_off = percent\_off;
if (amount\_off) {
couponParams.amount_off = amount_off;
couponParams.currency = currency || 'usd';
}
if (duration_in_months) couponParams.duration_in_months = duration_in_months;
if (max_redemptions) couponParams.max_redemptions = max\_redemptions;
if (redeem_by) couponParams.redeem_by = Math.floor(new Date(redeem\_by).getTime() / 1000);
const coupon = await stripe.coupons.create(couponParams);
res.status(201).json({
success: true,
coupon,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
// Get all coupons
app.get('/api/coupons', async (req, res) => {
try {
const { limit = 10 } = req.query;
const coupons = await stripe.coupons.list({ limit });
res.status(200).json({
success: true,
coupons: coupons.data,
has_more: coupons.has_more,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
// Get a specific coupon
app.get('/api/coupons/:id', async (req, res) => {
try {
const coupon = await stripe.coupons.retrieve(req.params.id);
res.status(200).json({
success: true,
coupon,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
// Delete a coupon
app.delete('/api/coupons/:id', async (req, res) => {
try {
const deleted = await stripe.coupons.del(req.params.id);
res.status(200).json({
success: true,
deleted,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
// Create a promotion code for a coupon
app.post('/api/promotion-codes', async (req, res) => {
try {
const {
coupon,
code,
max\_redemptions,
expires\_at,
metadata,
restrictions
} = req.body;
const params = { coupon };
if (code) params.code = code;
if (max_redemptions) params.max_redemptions = max\_redemptions;
if (expires_at) params.expires_at = Math.floor(new Date(expires\_at).getTime() / 1000);
if (metadata) params.metadata = metadata;
if (restrictions) params.restrictions = restrictions;
const promotionCode = await stripe.promotionCodes.create(params);
res.status(201).json({
success: true,
promotion\_code: promotionCode,
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message,
});
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Conclusion
In this comprehensive tutorial, we've covered everything you need to know about creating and managing coupon codes using the Stripe API:
By following these steps, you can implement a robust coupon system in your application using Stripe's powerful API. Remember to always test your implementation in Stripe's test environment before going live with real customers.
When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.