0
# Subscriptions
1
2
Stripe's subscription system provides comprehensive recurring billing capabilities with flexible pricing models, prorations, trials, and lifecycle management. This module handles everything from simple monthly subscriptions to complex usage-based billing.
3
4
## Core Subscription Resources
5
6
### Subscriptions
7
8
The primary resource for managing recurring billing relationships:
9
10
```typescript { .api }
11
interface Subscription {
12
id: string;
13
object: 'subscription';
14
customer: string;
15
status: 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid';
16
items: {
17
object: 'list';
18
data: SubscriptionItem[];
19
};
20
current_period_start: number;
21
current_period_end: number;
22
trial_start?: number;
23
trial_end?: number;
24
cancel_at_period_end: boolean;
25
default_payment_method?: string;
26
}
27
28
// Create subscription
29
const subscription = await stripe.subscriptions.create({
30
customer: 'cus_123',
31
items: [
32
{
33
price: 'price_monthly_premium',
34
quantity: 1
35
}
36
],
37
payment_behavior: 'default_incomplete',
38
payment_settings: {
39
save_default_payment_method: 'on_subscription'
40
},
41
expand: ['latest_invoice.payment_intent']
42
});
43
44
// Create subscription with trial
45
const trialSubscription = await stripe.subscriptions.create({
46
customer: 'cus_123',
47
items: [{ price: 'price_123' }],
48
trial_period_days: 14,
49
trial_settings: {
50
end_behavior: {
51
missing_payment_method: 'cancel'
52
}
53
}
54
});
55
56
// Create subscription with custom billing cycle
57
const customBilling = await stripe.subscriptions.create({
58
customer: 'cus_123',
59
items: [{ price: 'price_123' }],
60
billing_cycle_anchor: Math.floor(Date.now() / 1000) + 86400, // Start tomorrow
61
proration_behavior: 'create_prorations'
62
});
63
64
// Retrieve subscription
65
const retrieved = await stripe.subscriptions.retrieve('sub_123', {
66
expand: ['customer', 'default_payment_method', 'items.data.price']
67
});
68
69
// Update subscription
70
const updated = await stripe.subscriptions.update('sub_123', {
71
items: [
72
{
73
id: 'si_existing_item',
74
price: 'price_new_plan',
75
quantity: 2
76
}
77
],
78
proration_behavior: 'always_invoice',
79
payment_behavior: 'pending_if_incomplete'
80
});
81
82
// List subscriptions
83
const subscriptions = await stripe.subscriptions.list({
84
customer: 'cus_123',
85
status: 'active',
86
limit: 10
87
});
88
89
// Cancel subscription at period end
90
const canceled = await stripe.subscriptions.update('sub_123', {
91
cancel_at_period_end: true,
92
cancellation_details: {
93
comment: 'Customer requested cancellation'
94
}
95
});
96
97
// Cancel subscription immediately
98
const immediatelyCanceled = await stripe.subscriptions.cancel('sub_123', {
99
prorate: true,
100
invoice_now: true
101
});
102
103
// Resume canceled subscription
104
const resumed = await stripe.subscriptions.resume('sub_123', {
105
billing_cycle_anchor: 'now',
106
proration_behavior: 'create_prorations'
107
});
108
109
// Search subscriptions
110
const searchResults = await stripe.subscriptions.search({
111
query: 'status:"active" AND metadata["plan_type"]:"premium"'
112
});
113
```
114
115
### SubscriptionItems
116
117
Individual line items within a subscription:
118
119
```typescript { .api }
120
interface SubscriptionItem {
121
id: string;
122
object: 'subscription_item';
123
subscription: string;
124
price: Price;
125
quantity?: number;
126
tax_rates?: TaxRate[];
127
created: number;
128
}
129
130
// Create subscription item (add to existing subscription)
131
const subscriptionItem = await stripe.subscriptionItems.create({
132
subscription: 'sub_123',
133
price: 'price_addon_feature',
134
quantity: 1,
135
proration_behavior: 'always_invoice',
136
payment_behavior: 'pending_if_incomplete'
137
});
138
139
// Create usage-based subscription item
140
const usageItem = await stripe.subscriptionItems.create({
141
subscription: 'sub_123',
142
price: 'price_usage_based',
143
billing_thresholds: {
144
usage_gte: 1000 // Bill when usage >= 1000 units
145
}
146
});
147
148
// Retrieve subscription item
149
const retrieved = await stripe.subscriptionItems.retrieve('si_123', {
150
expand: ['price.product']
151
});
152
153
// Update subscription item
154
const updated = await stripe.subscriptionItems.update('si_123', {
155
quantity: 3,
156
price: 'price_upgraded_plan',
157
proration_behavior: 'create_prorations'
158
});
159
160
// List subscription items
161
const items = await stripe.subscriptionItems.list({
162
subscription: 'sub_123'
163
});
164
165
// Delete subscription item
166
const deleted = await stripe.subscriptionItems.del('si_123', {
167
proration_behavior: 'always_invoice',
168
clear_usage: true
169
});
170
```
171
172
### Usage Records
173
174
Track usage for metered billing:
175
176
```typescript { .api }
177
// Create usage record
178
const usageRecord = await stripe.subscriptionItems.createUsageRecord(
179
'si_usage_based',
180
{
181
quantity: 100,
182
timestamp: Math.floor(Date.now() / 1000),
183
action: 'increment' // or 'set'
184
}
185
);
186
187
// Create usage record with idempotency
188
const idempotentUsage = await stripe.subscriptionItems.createUsageRecord(
189
'si_usage_based',
190
{
191
quantity: 50,
192
timestamp: Math.floor(Date.now() / 1000),
193
action: 'increment'
194
},
195
{
196
idempotencyKey: 'usage_' + Date.now()
197
}
198
);
199
200
// List usage record summaries
201
const usageSummaries = await stripe.subscriptionItems.listUsageRecordSummaries(
202
'si_usage_based',
203
{
204
limit: 10,
205
ending_before: Math.floor(Date.now() / 1000)
206
}
207
);
208
```
209
210
## Subscription Schedules
211
212
Manage complex subscription lifecycle changes:
213
214
```typescript { .api }
215
interface SubscriptionSchedule {
216
id: string;
217
object: 'subscription_schedule';
218
customer: string;
219
status: 'not_started' | 'active' | 'completed' | 'released' | 'canceled';
220
subscription?: string;
221
phases: SubscriptionSchedulePhase[];
222
}
223
224
// Create subscription schedule
225
const schedule = await stripe.subscriptionSchedules.create({
226
customer: 'cus_123',
227
start_date: Math.floor(Date.now() / 1000) + 86400, // Start tomorrow
228
end_behavior: 'cancel',
229
phases: [
230
{
231
// Trial phase
232
items: [{ price: 'price_123', quantity: 1 }],
233
trial: true,
234
end_date: Math.floor(Date.now() / 1000) + 86400 * 14 // 14 days
235
},
236
{
237
// Regular billing phase
238
items: [{ price: 'price_123', quantity: 1 }],
239
iterations: 12 // 12 billing cycles
240
},
241
{
242
// Discounted renewal phase
243
items: [{ price: 'price_discounted', quantity: 1 }]
244
// No end_date = continues indefinitely
245
}
246
]
247
});
248
249
// Create schedule with price changes
250
const pricingSchedule = await stripe.subscriptionSchedules.create({
251
customer: 'cus_123',
252
phases: [
253
{
254
items: [{ price: 'price_starter', quantity: 1 }],
255
end_date: Math.floor(Date.now() / 1000) + 86400 * 90 // 3 months
256
},
257
{
258
items: [{ price: 'price_professional', quantity: 1 }],
259
proration_behavior: 'create_prorations'
260
}
261
]
262
});
263
264
// Retrieve subscription schedule
265
const retrieved = await stripe.subscriptionSchedules.retrieve('sub_sched_123', {
266
expand: ['subscription', 'phases.items.price']
267
});
268
269
// Update subscription schedule
270
const updated = await stripe.subscriptionSchedules.update('sub_sched_123', {
271
phases: [
272
{
273
items: [{ price: 'price_updated', quantity: 2 }],
274
start_date: Math.floor(Date.now() / 1000),
275
end_date: Math.floor(Date.now() / 1000) + 86400 * 30
276
}
277
]
278
});
279
280
// List subscription schedules
281
const schedules = await stripe.subscriptionSchedules.list({
282
customer: 'cus_123',
283
limit: 10
284
});
285
286
// Cancel subscription schedule
287
const canceled = await stripe.subscriptionSchedules.cancel('sub_sched_123');
288
289
// Release subscription schedule (convert to regular subscription)
290
const released = await stripe.subscriptionSchedule.release('sub_sched_123', {
291
preserve_cancel_date: true
292
});
293
```
294
295
## Legacy Plans
296
297
Legacy pricing model (use Prices for new integrations):
298
299
```typescript { .api }
300
interface Plan {
301
id: string;
302
object: 'plan';
303
amount?: number;
304
currency: string;
305
interval: 'day' | 'week' | 'month' | 'year';
306
interval_count: number;
307
nickname?: string;
308
product: string;
309
}
310
311
// Create plan (legacy - use Prices instead)
312
const plan = await stripe.plans.create({
313
id: 'gold-monthly',
314
amount: 2000,
315
currency: 'usd',
316
interval: 'month',
317
product: 'prod_gold_plan'
318
});
319
320
// Retrieve plan
321
const retrieved = await stripe.plans.retrieve('gold-monthly');
322
323
// Update plan
324
const updated = await stripe.plans.update('gold-monthly', {
325
nickname: 'Gold Monthly Plan',
326
metadata: { tier: 'premium' }
327
});
328
329
// List plans
330
const plans = await stripe.plans.list({
331
limit: 10,
332
active: true
333
});
334
335
// Delete plan
336
const deleted = await stripe.plans.del('gold-monthly');
337
```
338
339
## Invoicing
340
341
### Invoices
342
343
Billing documents for subscriptions and one-off charges:
344
345
```typescript { .api }
346
interface Invoice {
347
id: string;
348
object: 'invoice';
349
customer: string;
350
subscription?: string;
351
status: 'draft' | 'open' | 'paid' | 'uncollectible' | 'void';
352
amount_due: number;
353
amount_paid: number;
354
currency: string;
355
due_date?: number;
356
}
357
358
// Create invoice
359
const invoice = await stripe.invoices.create({
360
customer: 'cus_123',
361
collection_method: 'send_invoice',
362
days_until_due: 30,
363
description: 'Custom invoice for services'
364
});
365
366
// Create subscription invoice preview
367
const preview = await stripe.invoices.retrieveUpcoming({
368
customer: 'cus_123',
369
subscription: 'sub_123',
370
subscription_items: [
371
{
372
id: 'si_123',
373
quantity: 2
374
}
375
]
376
});
377
378
// Retrieve invoice
379
const retrieved = await stripe.invoices.retrieve('in_123', {
380
expand: ['payment_intent', 'customer']
381
});
382
383
// Update invoice
384
const updated = await stripe.invoices.update('in_123', {
385
description: 'Updated invoice description',
386
footer: 'Thank you for your business!',
387
metadata: { order_id: '12345' }
388
});
389
390
// List invoices
391
const invoices = await stripe.invoices.list({
392
customer: 'cus_123',
393
status: 'open',
394
limit: 10
395
});
396
397
// Finalize invoice
398
const finalized = await stripe.invoices.finalizeInvoice('in_123', {
399
auto_advance: true
400
});
401
402
// Pay invoice
403
const paid = await stripe.invoices.pay('in_123', {
404
payment_method: 'pm_card_visa',
405
paid_out_of_band: false
406
});
407
408
// Send invoice
409
const sent = await stripe.invoices.sendInvoice('in_123', {
410
delivery_method: 'email'
411
});
412
413
// Mark uncollectible
414
const uncollectible = await stripe.invoices.markUncollectible('in_123');
415
416
// Void invoice
417
const voided = await stripe.invoices.voidInvoice('in_123');
418
419
// Delete draft invoice
420
const deleted = await stripe.invoices.del('in_123');
421
422
// Search invoices
423
const searchResults = await stripe.invoices.search({
424
query: 'total>1000 AND status:"paid"'
425
});
426
427
// Get upcoming invoice line items
428
const upcomingLines = await stripe.invoices.upcomingLines({
429
customer: 'cus_123',
430
subscription: 'sub_123'
431
});
432
```
433
434
### InvoiceItems
435
436
Individual line items on invoices:
437
438
```typescript { .api }
439
interface InvoiceItem {
440
id: string;
441
object: 'invoiceitem';
442
customer: string;
443
amount: number;
444
currency: string;
445
description?: string;
446
invoice?: string;
447
subscription?: string;
448
}
449
450
// Create invoice item
451
const invoiceItem = await stripe.invoiceItems.create({
452
customer: 'cus_123',
453
amount: 2500,
454
currency: 'usd',
455
description: 'One-time setup fee'
456
});
457
458
// Create invoice item for specific invoice
459
const specificItem = await stripe.invoiceItems.create({
460
customer: 'cus_123',
461
amount: 1000,
462
currency: 'usd',
463
description: 'Custom charge',
464
invoice: 'in_123'
465
});
466
467
// Create invoice item with price
468
const priceBasedItem = await stripe.invoiceItems.create({
469
customer: 'cus_123',
470
price: 'price_setup_fee',
471
quantity: 1
472
});
473
474
// Retrieve invoice item
475
const retrieved = await stripe.invoiceItems.retrieve('ii_123');
476
477
// Update invoice item
478
const updated = await stripe.invoiceItems.update('ii_123', {
479
description: 'Updated setup fee',
480
amount: 3000,
481
metadata: { type: 'setup' }
482
});
483
484
// List invoice items
485
const invoiceItems = await stripe.invoiceItems.list({
486
customer: 'cus_123',
487
limit: 10
488
});
489
490
// Delete invoice item
491
const deleted = await stripe.invoiceItems.del('ii_123');
492
```
493
494
## Coupons and Discounts
495
496
### Coupons
497
498
Reusable discount definitions:
499
500
```typescript { .api }
501
interface Coupon {
502
id: string;
503
object: 'coupon';
504
name?: string;
505
percent_off?: number;
506
amount_off?: number;
507
currency?: string;
508
duration: 'forever' | 'once' | 'repeating';
509
duration_in_months?: number;
510
max_redemptions?: number;
511
times_redeemed: number;
512
valid: boolean;
513
}
514
515
// Create percentage coupon
516
const percentCoupon = await stripe.coupons.create({
517
id: 'SUMMER20',
518
percent_off: 20,
519
duration: 'repeating',
520
duration_in_months: 3,
521
max_redemptions: 100,
522
name: 'Summer Sale 20% Off'
523
});
524
525
// Create amount-based coupon
526
const amountCoupon = await stripe.coupons.create({
527
amount_off: 500,
528
currency: 'usd',
529
duration: 'once',
530
name: '$5 Off First Order'
531
});
532
533
// Create coupon with restrictions
534
const restrictedCoupon = await stripe.coupons.create({
535
percent_off: 15,
536
duration: 'forever',
537
applies_to: {
538
products: ['prod_premium_plan']
539
},
540
currency_options: {
541
eur: { amount_off: 450 },
542
gbp: { amount_off: 400 }
543
}
544
});
545
546
// Retrieve coupon
547
const retrieved = await stripe.coupons.retrieve('SUMMER20');
548
549
// Update coupon
550
const updated = await stripe.coupons.update('SUMMER20', {
551
name: 'Extended Summer Sale',
552
metadata: { campaign: 'summer_2024' }
553
});
554
555
// List coupons
556
const coupons = await stripe.coupons.list({
557
limit: 10
558
});
559
560
// Delete coupon
561
const deleted = await stripe.coupons.del('SUMMER20');
562
```
563
564
### PromotionCodes
565
566
Customer-facing codes that apply coupons:
567
568
```typescript { .api }
569
interface PromotionCode {
570
id: string;
571
object: 'promotion_code';
572
code: string;
573
coupon: Coupon;
574
active: boolean;
575
customer?: string;
576
expires_at?: number;
577
max_redemptions?: number;
578
times_redeemed: number;
579
}
580
581
// Create promotion code
582
const promotionCode = await stripe.promotionCodes.create({
583
coupon: 'SUMMER20',
584
code: 'SAVE20NOW',
585
max_redemptions: 50,
586
expires_at: Math.floor(Date.now() / 1000) + 86400 * 30 // 30 days
587
});
588
589
// Create customer-specific promotion code
590
const customerCode = await stripe.promotionCodes.create({
591
coupon: 'VIP10',
592
customer: 'cus_123',
593
code: 'VIPCUSTOMER'
594
});
595
596
// Auto-generate promotion code
597
const autoCode = await stripe.promotionCodes.create({
598
coupon: 'SUMMER20',
599
restrictions: {
600
minimum_amount: 1000,
601
minimum_amount_currency: 'usd'
602
}
603
});
604
605
// Retrieve promotion code
606
const retrieved = await stripe.promotionCodes.retrieve('promo_123');
607
608
// Update promotion code
609
const updated = await stripe.promotionCodes.update('promo_123', {
610
active: false,
611
metadata: { reason: 'expired_campaign' }
612
});
613
614
// List promotion codes
615
const promotionCodes = await stripe.promotionCodes.list({
616
coupon: 'SUMMER20',
617
active: true,
618
limit: 10
619
});
620
```
621
622
## Credit Notes
623
624
Issue credits for invoices:
625
626
```typescript { .api }
627
interface CreditNote {
628
id: string;
629
object: 'credit_note';
630
invoice: string;
631
customer: string;
632
amount: number;
633
currency: string;
634
status: 'issued' | 'void';
635
type: 'pre_payment' | 'post_payment';
636
}
637
638
// Create credit note
639
const creditNote = await stripe.creditNotes.create({
640
invoice: 'in_123',
641
lines: [
642
{
643
type: 'invoice_line_item',
644
invoice_line_item: 'il_123',
645
quantity: 1
646
}
647
],
648
reason: 'product_unsatisfactory'
649
});
650
651
// Create partial credit note
652
const partialCredit = await stripe.creditNotes.create({
653
invoice: 'in_123',
654
amount: 500,
655
reason: 'order_change'
656
});
657
658
// Preview credit note
659
const preview = await stripe.creditNotes.preview({
660
invoice: 'in_123',
661
amount: 1000
662
});
663
664
// Retrieve credit note
665
const retrieved = await stripe.creditNotes.retrieve('cn_123');
666
667
// Update credit note
668
const updated = await stripe.creditNotes.update('cn_123', {
669
memo: 'Refund for damaged item',
670
metadata: { return_id: '12345' }
671
});
672
673
// List credit notes
674
const creditNotes = await stripe.creditNotes.list({
675
customer: 'cus_123',
676
limit: 10
677
});
678
679
// Void credit note
680
const voided = await stripe.creditNotes.voidCreditNote('cn_123');
681
682
// List credit note line items
683
const lineItems = await stripe.creditNotes.listLineItems('cn_123');
684
```
685
686
## Tax Management
687
688
### TaxRates
689
690
Define tax rates for automatic tax calculation:
691
692
```typescript { .api }
693
interface TaxRate {
694
id: string;
695
object: 'tax_rate';
696
percentage: number;
697
display_name: string;
698
description?: string;
699
jurisdiction?: string;
700
inclusive: boolean;
701
active: boolean;
702
}
703
704
// Create tax rate
705
const taxRate = await stripe.taxRates.create({
706
display_name: 'VAT',
707
description: 'UK Value Added Tax',
708
percentage: 20.0,
709
inclusive: false,
710
jurisdiction: 'UK',
711
active: true
712
});
713
714
// Create inclusive tax rate
715
const inclusiveTax = await stripe.taxRates.create({
716
display_name: 'GST',
717
percentage: 10.0,
718
inclusive: true,
719
country: 'AU',
720
state: 'NSW'
721
});
722
723
// Retrieve tax rate
724
const retrieved = await stripe.taxRates.retrieve('txr_123');
725
726
// Update tax rate
727
const updated = await stripe.taxRates.update('txr_123', {
728
display_name: 'Updated VAT Rate',
729
active: false
730
});
731
732
// List tax rates
733
const taxRates = await stripe.taxRates.list({
734
active: true,
735
limit: 10
736
});
737
738
// Apply tax rate to subscription
739
const subscription = await stripe.subscriptions.create({
740
customer: 'cus_123',
741
items: [{
742
price: 'price_123',
743
tax_rates: ['txr_123']
744
}],
745
default_tax_rates: ['txr_123'] // Apply to all items by default
746
});
747
```
748
749
This comprehensive subscription system supports everything from simple recurring billing to complex multi-phase pricing strategies, usage-based billing, and sophisticated tax handling across global markets.