CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-stripe

Stripe API wrapper for Node.js providing comprehensive payment processing, subscription management, and financial services integration.

Pending
Overview
Eval results
Files

subscriptions.mddocs/

Subscriptions

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.

Core Subscription Resources

Subscriptions

The primary resource for managing recurring billing relationships:

interface Subscription {
  id: string;
  object: 'subscription';
  customer: string;
  status: 'incomplete' | 'incomplete_expired' | 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid';
  items: {
    object: 'list';
    data: SubscriptionItem[];
  };
  current_period_start: number;
  current_period_end: number;
  trial_start?: number;
  trial_end?: number;
  cancel_at_period_end: boolean;
  default_payment_method?: string;
}

// Create subscription
const subscription = await stripe.subscriptions.create({
  customer: 'cus_123',
  items: [
    {
      price: 'price_monthly_premium',
      quantity: 1
    }
  ],
  payment_behavior: 'default_incomplete',
  payment_settings: {
    save_default_payment_method: 'on_subscription'
  },
  expand: ['latest_invoice.payment_intent']
});

// Create subscription with trial
const trialSubscription = await stripe.subscriptions.create({
  customer: 'cus_123',
  items: [{ price: 'price_123' }],
  trial_period_days: 14,
  trial_settings: {
    end_behavior: {
      missing_payment_method: 'cancel'
    }
  }
});

// Create subscription with custom billing cycle
const customBilling = await stripe.subscriptions.create({
  customer: 'cus_123',
  items: [{ price: 'price_123' }],
  billing_cycle_anchor: Math.floor(Date.now() / 1000) + 86400, // Start tomorrow
  proration_behavior: 'create_prorations'
});

// Retrieve subscription
const retrieved = await stripe.subscriptions.retrieve('sub_123', {
  expand: ['customer', 'default_payment_method', 'items.data.price']
});

// Update subscription
const updated = await stripe.subscriptions.update('sub_123', {
  items: [
    {
      id: 'si_existing_item',
      price: 'price_new_plan',
      quantity: 2
    }
  ],
  proration_behavior: 'always_invoice',
  payment_behavior: 'pending_if_incomplete'
});

// List subscriptions
const subscriptions = await stripe.subscriptions.list({
  customer: 'cus_123',
  status: 'active',
  limit: 10
});

// Cancel subscription at period end
const canceled = await stripe.subscriptions.update('sub_123', {
  cancel_at_period_end: true,
  cancellation_details: {
    comment: 'Customer requested cancellation'
  }
});

// Cancel subscription immediately
const immediatelyCanceled = await stripe.subscriptions.cancel('sub_123', {
  prorate: true,
  invoice_now: true
});

// Resume canceled subscription
const resumed = await stripe.subscriptions.resume('sub_123', {
  billing_cycle_anchor: 'now',
  proration_behavior: 'create_prorations'
});

// Search subscriptions
const searchResults = await stripe.subscriptions.search({
  query: 'status:"active" AND metadata["plan_type"]:"premium"'
});

SubscriptionItems

Individual line items within a subscription:

interface SubscriptionItem {
  id: string;
  object: 'subscription_item';
  subscription: string;
  price: Price;
  quantity?: number;
  tax_rates?: TaxRate[];
  created: number;
}

// Create subscription item (add to existing subscription)
const subscriptionItem = await stripe.subscriptionItems.create({
  subscription: 'sub_123',
  price: 'price_addon_feature',
  quantity: 1,
  proration_behavior: 'always_invoice',
  payment_behavior: 'pending_if_incomplete'
});

// Create usage-based subscription item
const usageItem = await stripe.subscriptionItems.create({
  subscription: 'sub_123',
  price: 'price_usage_based',
  billing_thresholds: {
    usage_gte: 1000 // Bill when usage >= 1000 units
  }
});

// Retrieve subscription item
const retrieved = await stripe.subscriptionItems.retrieve('si_123', {
  expand: ['price.product']
});

// Update subscription item
const updated = await stripe.subscriptionItems.update('si_123', {
  quantity: 3,
  price: 'price_upgraded_plan',
  proration_behavior: 'create_prorations'
});

// List subscription items
const items = await stripe.subscriptionItems.list({
  subscription: 'sub_123'
});

// Delete subscription item
const deleted = await stripe.subscriptionItems.del('si_123', {
  proration_behavior: 'always_invoice',
  clear_usage: true
});

Usage Records

Track usage for metered billing:

// Create usage record
const usageRecord = await stripe.subscriptionItems.createUsageRecord(
  'si_usage_based',
  {
    quantity: 100,
    timestamp: Math.floor(Date.now() / 1000),
    action: 'increment' // or 'set'
  }
);

// Create usage record with idempotency
const idempotentUsage = await stripe.subscriptionItems.createUsageRecord(
  'si_usage_based',
  {
    quantity: 50,
    timestamp: Math.floor(Date.now() / 1000),
    action: 'increment'
  },
  {
    idempotencyKey: 'usage_' + Date.now()
  }
);

// List usage record summaries
const usageSummaries = await stripe.subscriptionItems.listUsageRecordSummaries(
  'si_usage_based',
  {
    limit: 10,
    ending_before: Math.floor(Date.now() / 1000)
  }
);

Subscription Schedules

Manage complex subscription lifecycle changes:

interface SubscriptionSchedule {
  id: string;
  object: 'subscription_schedule';
  customer: string;
  status: 'not_started' | 'active' | 'completed' | 'released' | 'canceled';
  subscription?: string;
  phases: SubscriptionSchedulePhase[];
}

// Create subscription schedule
const schedule = await stripe.subscriptionSchedules.create({
  customer: 'cus_123',
  start_date: Math.floor(Date.now() / 1000) + 86400, // Start tomorrow
  end_behavior: 'cancel',
  phases: [
    {
      // Trial phase
      items: [{ price: 'price_123', quantity: 1 }],
      trial: true,
      end_date: Math.floor(Date.now() / 1000) + 86400 * 14 // 14 days
    },
    {
      // Regular billing phase
      items: [{ price: 'price_123', quantity: 1 }],
      iterations: 12 // 12 billing cycles
    },
    {
      // Discounted renewal phase
      items: [{ price: 'price_discounted', quantity: 1 }]
      // No end_date = continues indefinitely
    }
  ]
});

// Create schedule with price changes
const pricingSchedule = await stripe.subscriptionSchedules.create({
  customer: 'cus_123',
  phases: [
    {
      items: [{ price: 'price_starter', quantity: 1 }],
      end_date: Math.floor(Date.now() / 1000) + 86400 * 90 // 3 months
    },
    {
      items: [{ price: 'price_professional', quantity: 1 }],
      proration_behavior: 'create_prorations'
    }
  ]
});

// Retrieve subscription schedule
const retrieved = await stripe.subscriptionSchedules.retrieve('sub_sched_123', {
  expand: ['subscription', 'phases.items.price']
});

// Update subscription schedule
const updated = await stripe.subscriptionSchedules.update('sub_sched_123', {
  phases: [
    {
      items: [{ price: 'price_updated', quantity: 2 }],
      start_date: Math.floor(Date.now() / 1000),
      end_date: Math.floor(Date.now() / 1000) + 86400 * 30
    }
  ]
});

// List subscription schedules
const schedules = await stripe.subscriptionSchedules.list({
  customer: 'cus_123',
  limit: 10
});

// Cancel subscription schedule
const canceled = await stripe.subscriptionSchedules.cancel('sub_sched_123');

// Release subscription schedule (convert to regular subscription)
const released = await stripe.subscriptionSchedule.release('sub_sched_123', {
  preserve_cancel_date: true
});

Legacy Plans

Legacy pricing model (use Prices for new integrations):

interface Plan {
  id: string;
  object: 'plan';
  amount?: number;
  currency: string;
  interval: 'day' | 'week' | 'month' | 'year';
  interval_count: number;
  nickname?: string;
  product: string;
}

// Create plan (legacy - use Prices instead)
const plan = await stripe.plans.create({
  id: 'gold-monthly',
  amount: 2000,
  currency: 'usd',
  interval: 'month',
  product: 'prod_gold_plan'
});

// Retrieve plan
const retrieved = await stripe.plans.retrieve('gold-monthly');

// Update plan
const updated = await stripe.plans.update('gold-monthly', {
  nickname: 'Gold Monthly Plan',
  metadata: { tier: 'premium' }
});

// List plans
const plans = await stripe.plans.list({
  limit: 10,
  active: true
});

// Delete plan
const deleted = await stripe.plans.del('gold-monthly');

Invoicing

Invoices

Billing documents for subscriptions and one-off charges:

interface Invoice {
  id: string;
  object: 'invoice';
  customer: string;
  subscription?: string;
  status: 'draft' | 'open' | 'paid' | 'uncollectible' | 'void';
  amount_due: number;
  amount_paid: number;
  currency: string;
  due_date?: number;
}

// Create invoice
const invoice = await stripe.invoices.create({
  customer: 'cus_123',
  collection_method: 'send_invoice',
  days_until_due: 30,
  description: 'Custom invoice for services'
});

// Create subscription invoice preview
const preview = await stripe.invoices.retrieveUpcoming({
  customer: 'cus_123',
  subscription: 'sub_123',
  subscription_items: [
    {
      id: 'si_123',
      quantity: 2
    }
  ]
});

// Retrieve invoice
const retrieved = await stripe.invoices.retrieve('in_123', {
  expand: ['payment_intent', 'customer']
});

// Update invoice
const updated = await stripe.invoices.update('in_123', {
  description: 'Updated invoice description',
  footer: 'Thank you for your business!',
  metadata: { order_id: '12345' }
});

// List invoices
const invoices = await stripe.invoices.list({
  customer: 'cus_123',
  status: 'open',
  limit: 10
});

// Finalize invoice
const finalized = await stripe.invoices.finalizeInvoice('in_123', {
  auto_advance: true
});

// Pay invoice
const paid = await stripe.invoices.pay('in_123', {
  payment_method: 'pm_card_visa',
  paid_out_of_band: false
});

// Send invoice
const sent = await stripe.invoices.sendInvoice('in_123', {
  delivery_method: 'email'
});

// Mark uncollectible
const uncollectible = await stripe.invoices.markUncollectible('in_123');

// Void invoice
const voided = await stripe.invoices.voidInvoice('in_123');

// Delete draft invoice
const deleted = await stripe.invoices.del('in_123');

// Search invoices
const searchResults = await stripe.invoices.search({
  query: 'total>1000 AND status:"paid"'
});

// Get upcoming invoice line items
const upcomingLines = await stripe.invoices.upcomingLines({
  customer: 'cus_123',
  subscription: 'sub_123'
});

InvoiceItems

Individual line items on invoices:

interface InvoiceItem {
  id: string;
  object: 'invoiceitem';
  customer: string;
  amount: number;
  currency: string;
  description?: string;
  invoice?: string;
  subscription?: string;
}

// Create invoice item
const invoiceItem = await stripe.invoiceItems.create({
  customer: 'cus_123',
  amount: 2500,
  currency: 'usd',
  description: 'One-time setup fee'
});

// Create invoice item for specific invoice
const specificItem = await stripe.invoiceItems.create({
  customer: 'cus_123',
  amount: 1000,
  currency: 'usd',
  description: 'Custom charge',
  invoice: 'in_123'
});

// Create invoice item with price
const priceBasedItem = await stripe.invoiceItems.create({
  customer: 'cus_123',
  price: 'price_setup_fee',
  quantity: 1
});

// Retrieve invoice item
const retrieved = await stripe.invoiceItems.retrieve('ii_123');

// Update invoice item
const updated = await stripe.invoiceItems.update('ii_123', {
  description: 'Updated setup fee',
  amount: 3000,
  metadata: { type: 'setup' }
});

// List invoice items
const invoiceItems = await stripe.invoiceItems.list({
  customer: 'cus_123',
  limit: 10
});

// Delete invoice item
const deleted = await stripe.invoiceItems.del('ii_123');

Coupons and Discounts

Coupons

Reusable discount definitions:

interface Coupon {
  id: string;
  object: 'coupon';
  name?: string;
  percent_off?: number;
  amount_off?: number;
  currency?: string;
  duration: 'forever' | 'once' | 'repeating';
  duration_in_months?: number;
  max_redemptions?: number;
  times_redeemed: number;
  valid: boolean;
}

// Create percentage coupon
const percentCoupon = await stripe.coupons.create({
  id: 'SUMMER20',
  percent_off: 20,
  duration: 'repeating',
  duration_in_months: 3,
  max_redemptions: 100,
  name: 'Summer Sale 20% Off'
});

// Create amount-based coupon
const amountCoupon = await stripe.coupons.create({
  amount_off: 500,
  currency: 'usd',
  duration: 'once',
  name: '$5 Off First Order'
});

// Create coupon with restrictions
const restrictedCoupon = await stripe.coupons.create({
  percent_off: 15,
  duration: 'forever',
  applies_to: {
    products: ['prod_premium_plan']
  },
  currency_options: {
    eur: { amount_off: 450 },
    gbp: { amount_off: 400 }
  }
});

// Retrieve coupon
const retrieved = await stripe.coupons.retrieve('SUMMER20');

// Update coupon
const updated = await stripe.coupons.update('SUMMER20', {
  name: 'Extended Summer Sale',
  metadata: { campaign: 'summer_2024' }
});

// List coupons
const coupons = await stripe.coupons.list({
  limit: 10
});

// Delete coupon
const deleted = await stripe.coupons.del('SUMMER20');

PromotionCodes

Customer-facing codes that apply coupons:

interface PromotionCode {
  id: string;
  object: 'promotion_code';
  code: string;
  coupon: Coupon;
  active: boolean;
  customer?: string;
  expires_at?: number;
  max_redemptions?: number;
  times_redeemed: number;
}

// Create promotion code
const promotionCode = await stripe.promotionCodes.create({
  coupon: 'SUMMER20',
  code: 'SAVE20NOW',
  max_redemptions: 50,
  expires_at: Math.floor(Date.now() / 1000) + 86400 * 30 // 30 days
});

// Create customer-specific promotion code
const customerCode = await stripe.promotionCodes.create({
  coupon: 'VIP10',
  customer: 'cus_123',
  code: 'VIPCUSTOMER'
});

// Auto-generate promotion code
const autoCode = await stripe.promotionCodes.create({
  coupon: 'SUMMER20',
  restrictions: {
    minimum_amount: 1000,
    minimum_amount_currency: 'usd'
  }
});

// Retrieve promotion code
const retrieved = await stripe.promotionCodes.retrieve('promo_123');

// Update promotion code
const updated = await stripe.promotionCodes.update('promo_123', {
  active: false,
  metadata: { reason: 'expired_campaign' }
});

// List promotion codes
const promotionCodes = await stripe.promotionCodes.list({
  coupon: 'SUMMER20',
  active: true,
  limit: 10
});

Credit Notes

Issue credits for invoices:

interface CreditNote {
  id: string;
  object: 'credit_note';
  invoice: string;
  customer: string;
  amount: number;
  currency: string;
  status: 'issued' | 'void';
  type: 'pre_payment' | 'post_payment';
}

// Create credit note
const creditNote = await stripe.creditNotes.create({
  invoice: 'in_123',
  lines: [
    {
      type: 'invoice_line_item',
      invoice_line_item: 'il_123',
      quantity: 1
    }
  ],
  reason: 'product_unsatisfactory'
});

// Create partial credit note
const partialCredit = await stripe.creditNotes.create({
  invoice: 'in_123',
  amount: 500,
  reason: 'order_change'
});

// Preview credit note
const preview = await stripe.creditNotes.preview({
  invoice: 'in_123',
  amount: 1000
});

// Retrieve credit note
const retrieved = await stripe.creditNotes.retrieve('cn_123');

// Update credit note
const updated = await stripe.creditNotes.update('cn_123', {
  memo: 'Refund for damaged item',
  metadata: { return_id: '12345' }
});

// List credit notes
const creditNotes = await stripe.creditNotes.list({
  customer: 'cus_123',
  limit: 10
});

// Void credit note
const voided = await stripe.creditNotes.voidCreditNote('cn_123');

// List credit note line items
const lineItems = await stripe.creditNotes.listLineItems('cn_123');

Tax Management

TaxRates

Define tax rates for automatic tax calculation:

interface TaxRate {
  id: string;
  object: 'tax_rate';
  percentage: number;
  display_name: string;
  description?: string;
  jurisdiction?: string;
  inclusive: boolean;
  active: boolean;
}

// Create tax rate
const taxRate = await stripe.taxRates.create({
  display_name: 'VAT',
  description: 'UK Value Added Tax',
  percentage: 20.0,
  inclusive: false,
  jurisdiction: 'UK',
  active: true
});

// Create inclusive tax rate
const inclusiveTax = await stripe.taxRates.create({
  display_name: 'GST',
  percentage: 10.0,
  inclusive: true,
  country: 'AU',
  state: 'NSW'
});

// Retrieve tax rate
const retrieved = await stripe.taxRates.retrieve('txr_123');

// Update tax rate
const updated = await stripe.taxRates.update('txr_123', {
  display_name: 'Updated VAT Rate',
  active: false
});

// List tax rates
const taxRates = await stripe.taxRates.list({
  active: true,
  limit: 10
});

// Apply tax rate to subscription
const subscription = await stripe.subscriptions.create({
  customer: 'cus_123',
  items: [{
    price: 'price_123',
    tax_rates: ['txr_123']
  }],
  default_tax_rates: ['txr_123'] // Apply to all items by default
});

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.

Install with Tessl CLI

npx tessl i tessl/npm-stripe

docs

billing.md

checkout.md

configuration.md

core-resources.md

identity.md

index.md

issuing.md

radar.md

subscriptions.md

tax.md

terminal.md

treasury.md

webhooks.md

tile.json