Back to list
useautumn

billing

by useautumn

Autumn is an open-source pricing & billing platform

2,309🍴 178📅 Jan 22, 2026

Use Cases

Work Efficiency

Streamline daily tasks and improve productivity.

📋

Project Management

Assist with task management and project tracking.

👥

Team Collaboration

Improve team communication and collaboration.

SKILL.md


name: billing description: Debug, edit, and fix billing endpoints. Covers legacy endpoints (attach/checkout/cancel) and the new v2 4-layer architecture (setup, compute, evaluate, execute). Use when working on billing, subscription, invoicing, or Stripe integration code.

Billing Endpoints Guide

When to Use This Skill

  • Debugging billing issues (double charges, missing invoices, wrong subscription items)
  • Adding new billing endpoints
  • Understanding how Autumn state maps to Stripe
  • Fixing subscription update/cancel/attach flows
  • Working with subscription schedules (future changes)

Endpoint Quick Reference

OperationHandlerArchitectureNotes
Attach productbilling/attach/handleAttach.tsLegacyAdds product to customer
Checkoutbilling/checkout/handleCheckoutV2.tsLegacyCreates Stripe checkout session
Cancelcustomers/cancel/handleCancel.tsLegacyCancels subscription
Update subscriptionbilling/v2/updateSubscription/handleUpdateSubscription.tsV2Quantity/plan changes

All new billing endpoints MUST use V2 architecture.

V2 Architecture: The 4-Layer Pattern

Every V2 billing endpoint follows this exact pattern. Copy this template:

// From: billing/v2/updateSubscription/handleUpdateSubscription.ts

export const handleUpdateSubscription = createRoute({
  body: UpdateSubscriptionV0ParamsSchema,
  handler: async (c) => {
    const ctx = c.get("ctx");
    const body = c.req.valid("json");

    // 1. SETUP - Fetch all context needed for billing operation
    const billingContext = await setupUpdateSubscriptionBillingContext({
      ctx,
      params: body,
    });
    logUpdateSubscriptionContext({ ctx, billingContext });

    // 2. COMPUTE - Determine Autumn state changes
    const autumnBillingPlan = await computeUpdateSubscriptionPlan({
      ctx,
      billingContext,
      params: body,
    });
    logUpdateSubscriptionPlan({ ctx, plan: autumnBillingPlan, billingContext });

    // 3. ERROR HANDLING - Validate before execution
    await handleUpdateSubscriptionErrors({
      ctx,
      billingContext,
      autumnBillingPlan,
      params: body,
    });

    // 4. EVALUATE - Map Autumn changes to Stripe changes (UNIFIED)
    const stripeBillingPlan = await evaluateStripeBillingPlan({
      ctx,
      billingContext,
      autumnBillingPlan,
    });
    logStripeBillingPlan({ ctx, stripeBillingPlan, billingContext });

    // 5. EXECUTE - Run Stripe actions, then Autumn DB updates
    const billingResult = await executeBillingPlan({
      ctx,
      billingContext,
      billingPlan: {
        autumn: autumnBillingPlan,
        stripe: stripeBillingPlan,
      },
    });

    const response = billingResultToResponse({ billingContext, billingResult });
    return c.json(response, 200);
  },
});

Key principle: evaluateStripeBillingPlan and executeBillingPlan are UNIFIED across all endpoints. Rarely modify them.

See V2 Four-Layer Pattern Deep Dive for detailed explanation.

Two Critical Stripe Mappings

Getting billing right means getting these two mappings right:

1. Subscription Items (Immediate Changes)

When: Updating a subscription right now (add/remove/change items immediately)

Key function: buildStripeSubscriptionItemsUpdate

Flow:

FullCusProduct[] 
  → filter by subscription ID
  → filter by active statuses  
  → customerProductToStripeItemSpecs() 
  → diff against current subscription
  → Stripe.SubscriptionUpdateParams.Item[]

See Stripe Subscription Items Reference for details.

2. Schedule Phases (Future Changes)

When: Scheduling changes for the future (downgrades at cycle end, scheduled cancellations)

Key function: buildStripePhasesUpdate

Flow:

FullCusProduct[]
  → normalize timestamps to seconds
  → buildTransitionPoints() (find all start/end times)
  → for each period: filter active products
  → customerProductsToPhaseItems()
  → Stripe.SubscriptionScheduleUpdateParams.Phase[]

Test reference: tests/unit/billing/stripe/subscription-schedules/build-schedule-phases.spec.ts

See Stripe Schedule Phases Reference for details.

Stripe Invoice Decision Tree

Critical: Stripe sometimes forces invoice creation. If you also create a manual invoice, customer gets double-charged.

Does Stripe force-create an invoice?
├── Creating a new subscription? 
│   └── YES → Stripe creates invoice. DO NOT create manual invoice.
│
├── Removing trial from subscription? (isTrialing && !willBeTrialing)
│   └── YES → Stripe creates invoice. DO NOT create manual invoice.
│
└── Otherwise
    └── NO → We create manual invoice using buildStripeInvoiceAction()

Key functions:

  • shouldCreateManualStripeInvoice() - Returns true if WE should create invoice
  • willStripeSubscriptionUpdateCreateInvoice() - Returns true if STRIPE will create invoice

See Stripe Invoice Rules Reference for full decision tree.

Common Issues & Fixes

SymptomLikely CauseQuick Fix
Double invoice chargeCreated manual invoice when Stripe already didCheck shouldCreateManualStripeInvoice()
Subscription items wrongcustomerProductToStripeItemSpecs output incorrectDebug spec generation, check quantity rules
Schedule phases wrongTransition points incorrectCheck buildTransitionPoints, run schedule phases tests
Trial not endingtrialContext not set up correctlyCheck setupTrialContext
Quantities wrongMetered vs licensed confusionundefined = metered, 0 = entity placeholder, N = licensed

See Common Bugs Reference for detailed debugging steps.

Adding a New Billing Endpoint

  1. Create setup function: setup/setupXxxBillingContext.ts

    • Extend BillingContext interface if needed
    • Fetch customer, products, Stripe state, timestamps
  2. Create compute function: compute/computeXxxPlan.ts

    • Return AutumnBillingPlan with insertCustomerProducts, deleteCustomerProduct, lineItems
  3. Create error handler: errors/handleXxxErrors.ts

    • Validate before execution
  4. Wire up handler: handleXxx.ts

    • Use the 4-layer template above
  5. DO NOT modify evaluateStripeBillingPlan or executeBillingPlan unless absolutely necessary

See V2 Four-Layer Pattern for detailed guidance.

Invoicing Utilities (Pure Calculations)

The shared/utils/billingUtils/ folder contains pure calculation functions that determine what customers are charged. These are the foundation of all billing operations.

Key utilities:

FunctionLocationPurpose
priceToLineAmountinvoicingUtils/lineItemUtils/Calculate charge amount for a price
tiersToLineAmountinvoicingUtils/lineItemUtils/Calculate tiered/usage-based amounts
applyProrationinvoicingUtils/prorationUtils/Calculate partial period charges
buildLineIteminvoicingUtils/lineItemBuilders/Core line item builder
fixedPriceToLineIteminvoicingUtils/lineItemBuilders/Build line item for fixed prices
usagePriceToLineIteminvoicingUtils/lineItemBuilders/Build line item for usage prices
getCycleEndcycleUtils/Calculate billing cycle end
getCycleStartcycleUtils/Calculate billing cycle start

Key concepts:

  • LineItem.amount is positive for charges, negative for refunds
  • context.direction controls the sign ("charge" vs "refund")
  • Proration is applied automatically when billingPeriod is provided
  • Consumable prices don't prorate (usage is charged as-is)

See Invoicing Utilities Reference for detailed documentation.

Key File Locations

V2 Billing (server/src/internal/billing/v2/)

LayerKey Files
Setupsetup/setupFullCustomerContext.ts, setup/setupTrialContext.ts, providers/stripe/setup/setupStripeBillingContext.ts
ComputeupdateSubscription/compute/computeUpdateSubscriptionPlan.ts, compute/computeAutumnUtils/buildAutumnLineItems.ts
Evaluateproviders/stripe/actionBuilders/evaluateStripeBillingPlan.ts, providers/stripe/actionBuilders/buildStripeSubscriptionAction.ts
Executeexecute/executeBillingPlan.ts, providers/stripe/execute/executeStripeBillingPlan.ts

Stripe Mapping Utilities

PurposeFile
Customer product → Stripe item specsproviders/stripe/utils/subscriptionItems/customerProductToStripeItemSpecs.ts
Build subscription items updateproviders/stripe/utils/subscriptionItems/buildStripeSubscriptionItemsUpdate.ts
Build schedule phasesproviders/stripe/utils/subscriptionSchedules/buildStripePhasesUpdate.ts
Build transition pointsproviders/stripe/utils/subscriptionSchedules/buildTransitionPoints.ts
Check if Stripe creates invoiceproviders/stripe/utils/invoices/shouldCreateManualStripeInvoice.ts

Types

TypeLocationPurpose
BillingContextbillingContext.tsCustomer, products, Stripe state, timestamps
AutumnBillingPlantypes/autumnBillingPlan.tsAutumn state changes (inserts, deletes, line items)
StripeBillingPlantypes/stripeBillingPlan/stripeBillingPlan.tsStripe actions (subscription, invoice, schedule)

Invoicing Utilities (shared/utils/billingUtils/)

PurposeFile
Amount calculationsinvoicingUtils/lineItemUtils/priceToLineAmount.ts, tiersToLineAmount.ts
Line item buildersinvoicingUtils/lineItemBuilders/buildLineItem.ts, fixedPriceToLineItem.ts, usagePriceToLineItem.ts
ProrationinvoicingUtils/prorationUtils/applyProration.ts
Billing cyclescycleUtils/getCycleEnd.ts, getCycleStart.ts

Tests

WhatLocation
Schedule phasestests/unit/billing/stripe/subscription-schedules/build-schedule-phases.spec.ts

Reference Files

Load these on-demand for detailed information:

Score

Total Score

80/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 1000以上

+15
最近の活動

3ヶ月以内に更新

+5
フォーク

10回以上フォークされている

+5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon