AS
AgSkills.dev
MARKETPLACE

billing

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.

2.3k
179

Preview

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:

GitHub Repository
useautumn/autumn
Stars
2,336
Forks
179
Open Repository
Install Skill
Download ZIP7 files