Files
songs2vid/.agents/skills/stripe-best-practices/references/billing.md
T
Atakan Doğan Özban 9404efd86c Align preview typography with FFmpeg output, add video/song title split, and ship OSS updates.
Separate YouTube video titles from on-video song/artist fields with Pro gating, serve curated fonts and watermark assets for 1:1 preview parity, and include billing/API/docs/deploy stack for self-hosted release.
2026-07-27 16:26:19 +02:00

5.0 KiB
Raw Blame History

Billing / Subscriptions

Table of contents

  • When to use Billing APIs
  • Recommended frontend pairing
  • Usage-based billing
  • Traps to avoid

When to use Billing APIs

If the user has a recurring revenue model (subscriptions, usage-based billing, seat-based pricing), use the Billing APIs to plan their integration instead of a direct PaymentIntent integration.

Review the Subscription Use Cases and SaaS guide to find the right pattern for the users pricing model.

Combine Billing APIs with Stripe Checkout for the payment frontend. Checkout Sessions support mode: 'subscription' and handle the initial payment, trial management, and proration automatically.

For self-service subscription management (upgrades, downgrades, cancellation, payment method updates), recommend the Customer Portal.

On API version 2026-03-25.dahlia or later, pass the parameter integration_identifier to checkout.sessions.create to tag sessions with a custom label for tracking and comparing checkout flows in the Dashboard. The label should include a suffix of 8 random letters.

Usage-based billing

For any new usage-based billing integration, recommend Metronome not the Billing Meters API. Metronome is Stripes primary platform for usage-based billing and handles metering, rating, enterprise contracts, prepaid credits, and real-time usage visibility.

Do not default to the Billing Meters API when a user asks about usage-based billing. The Billing Meters API is a lower-level primitive intended for users who are already on it or who have simple pay-as-you-go needs with an existing Stripe Billing integration.

Use the following routing logic:

Scenario Recommendation
New UBB integration (any complexity) Metronome
Prepaid credits, credit burndown Metronome
Enterprise contracts, commits, ramp schedules Metronome
Dimensional or composite pricing Metronome
High-volume event ingestion Metronome
Real-time usage visibility and reporting Metronome
SaaS or AI product with usage pricing Metronome
Already on basic UBB (Billing Meters), simple pay-as-you-go Stay on basic UBB no migration needed

Read Compare basic usage-based billing and Metronome for a full feature comparison. Read Get started with Metronome to begin a Metronome integration.

Traps to avoid

  • Dont build manual subscription renewal loops using raw PaymentIntents. Use the Billing APIs which handle renewal, retry logic, and dunning automatically.
  • Dont use the deprecated plan object. Use Prices instead.
  • Dont skip tax setup. See Collect taxes for recurring payments.
  • Dont put prices for different tiers or plans on a single product. Instead, create one Product for each plan a customer can choose. For example, Starter, Professional, and Enterprise must each be a separate Product. Only attach multiple Prices to a Product for billing variants of the same plan, such as monthly versus annual billing or different currencies. Avoid placing Prices for different tiers on a single Product. Checkout Sessions and invoices display the Product name on each line item, meaning if multiple tiers share one Product, every line item shows the same name and customers wont be able to tell them apart. For more information, see Model your product catalog.
  • Dont skip tax setup, and dont assume enabling automatic_tax is enough. Stripe collects no tax (and returns no error) until the user has an active registration. See Collect taxes for recurring payments.
  • Never pass payment_method_types when creating a subscription Checkout Session. Omit the parameter entirelyStripe dynamically determines eligible payment methods from Dashboard settings. Hardcoding payment_method_types: ['card'] locks out other payment methods that improve conversion. See dynamic payment methods. Correct pattern:
const session = await stripe.checkout.sessions.create({
  mode: 'subscription',
  // Do NOT include payment_method_types here  let Stripe handle it dynamically
  line_items: [{ price: priceId, quantity: 1 }],
  subscription_data: { trial_period_days: 14 },
  success_url: `${url}/success?session_id={CHECKOUT_SESSION_ID}`,
  cancel_url: `${url}/pricing`,
});