Stop building
billing infrastructure.
You shouldn't be writing code for trials, retries, dunning, pause logic, or reconciliation scripts. Define a plan, attach a customer, and Flint handles every billing cycle automatically.
// cron job, retry queue, webhook handler,// reconciliation script, state machine,// dunning emails, proration calculator...//// 2 months later: more billing code// than product code.
const sub = await flint.subscriptions.create({customerId: "cus_01HZ4X8",planId: "pln_01HZ8K3",paymentMethodId: "pm_01HZ8K4",});// sub.status → "TRIALING"// Flint handles everything else.
The problem
You wanted a $29/month plan.
Two months later you have a billing state machine, a cron job, a retry queue, a webhook handler, and a reconciliation script. You've written more billing code than product code. Every edge case you thought was simple turned out to be a week of work.
Trials need timers that fire at exactly the right moment. Failed payments need retries with exponential backoff and a decision about what happens when retries run out.
Pausing needs to freeze the billing cycle without losing the customer's place. Cancellation needs to respect contract terms, handle prorations, and clean up downstream state. Each of these is a mini-system you have to build, test, and maintain forever.
Subscription billing is a solved problem. You shouldn't have to re-solve it.
See the difference
What subscription billing actually looks like.
Same outcome - a customer on a recurring plan. One approach requires a billing engine. The other requires three API calls.
// 1. Create a productconst product = await stripe.products.create({name: "Pro Plan",});// 2. Create a priceconst price = await stripe.prices.create({product: product.id,unit_amount: 4900,currency: "usd",recurring: { interval: "month" },});// 3. Create or retrieve a customerconst customer = await stripe.customers.create({email: "user@example.com",});// 4. Attach a payment methodawait stripe.paymentMethods.attach(pmId, {customer: customer.id,});await stripe.customers.update(customer.id, {invoice_settings: {default_payment_method: pmId,},});// 5. Create the subscriptionconst sub = await stripe.subscriptions.create({customer: customer.id,items: [{ price: price.id }],trial_period_days: 14,});// 6. Handle webhook events:// invoice.created// invoice.payment_succeeded// invoice.payment_failed// customer.subscription.updated// customer.subscription.deleted// customer.subscription.trial_will_end
// 1. Create a plan (product + price in one)const plan = await flint.subscriptionPlans.create({name: "Pro Plan",billingInterval: "MONTHLY",currency: "USD",lineItems: [{name: "Pro seat license",quantity: 1,unitPriceMoney: { amount: 4900, currency: "USD" },}],trialPeriodDays: 14,});// 2. Save a payment methodconst pm = await flint.paymentMethods.save({customerId: "cus_01HZ4X8",sourceToken: "tok_visa",setAsDefault: true,});// 3. Start the subscriptionconst sub = await flint.subscriptions.create({customerId: "cus_01HZ4X8",planId: plan.id,paymentMethodId: pm.id,});// That's it. Flint handles:// - Trial → Active transition// - Billing cycle charges// - Failed payment retries// - Lifecycle webhooks// - Order creation per cycle
Code examples
From zero to recurring billing in three calls.
Create a plan, save a payment method, and start a subscription. Flint computes the billing schedule and handles every renewal.
Create a subscription plan
create-plan.ts
Save a payment method
save-payment-method.ts
Create a subscription
create-subscription.ts
const plan = await flint.subscriptionPlans.create({name: "Pro Monthly",billingInterval: "MONTHLY",currency: "USD",lineItems: [{name: "Pro seat license",quantity: 1,unitPriceMoney: { amount: 4900, currency: "USD" },},],trialPeriodDays: 14,});// plan.id → "pln_01HZ8K3"// plan.status → "ACTIVE"
const paymentMethod = await flint.paymentMethods.save({customerId: "cus_01HZ4X8",sourceToken: "tok_visa",setAsDefault: true,});// paymentMethod.id → "pm_01HZ8K4"// paymentMethod.card.last4 → "4242"// paymentMethod.isDefault → true
const subscription = await flint.subscriptions.create({customerId: "cus_01HZ4X8",planId: "pln_01HZ8K3",paymentMethodId: "pm_01HZ8K4",});// subscription.id → "sub_01HZ8K5"// subscription.status → "TRIALING"// subscription.trialEnd → "2026-04-13T00:00:00Z"// subscription.nextBillingDate → "2026-04-13T00:00:00Z"// Each billing cycle creates a Flint Order - same as one-off purchases.
Orders-native billing
Every billing cycle is a real order.
Most billing APIs create invoices that live in a separate system from your orders. Flint creates a real Order for every billing cycle - the same Order object you use for one-off purchases.
{"id": "ord_01HZ9A3","status": "PAID","source": "SUBSCRIPTION","subscriptionId": "sub_01HZ8K5","lineItems": [{"name": "Pro seat license","quantity": 1,"unitPriceMoney": { "amount": 4900, "currency": "USD" }}],"netAmounts": {"subtotalMoney": { "amount": 4900, "currency": "USD" },"taxMoney": { "amount": 392, "currency": "USD" },"totalMoney": { "amount": 5292, "currency": "USD" },"paidMoney": { "amount": 5292, "currency": "USD" },"balanceMoney": { "amount": 0, "currency": "USD" }}}
What's included
Everything a recurring billing API needs.
No separate dunning service, no pause logic to build, no webhook plumbing. Subscriptions handle it.
Flexible billing cadences
Monthly, yearly, or custom intervals via billingIntervalCount. Bill every 3 months, every 6 weeks, or any cycle your business needs. Multiple line items per plan with independent quantities and prices.
Free trials
Set trialPeriodDays on any plan. The subscription starts in TRIALING status and automatically transitions to ACTIVE when the trial ends. First charge happens on the transition - no manual scheduling.
Dunning & retries
Failed payments trigger automatic retries with configurable backoff. Subscriptions move to PAST_DUE and recover when payment succeeds. Configure the end action: cancel the subscription or pause it.
Pause & resume
Pause a subscription with one API call. Billing stops immediately. Set optional pauseDurationCycles to auto-resume after a set number of cycles, or resume manually when the customer returns.
Contract terms
Set contractTermMonths for minimum commitment periods. Cancellations before the term ends can apply an earlyTerminationFee or be blocked entirely. You control the policy per plan.
Real-time webhooks
Events for every lifecycle change: subscription.created, subscription.renewed, subscription.past_due, subscription.canceled, subscription.paused, subscription.resumed. Build automations without polling.
Lifecycle
Predictable subscription status machine.
Every subscription follows a deterministic lifecycle. Transitions are enforced server-side - no ambiguous states, no manual bookkeeping.
Keep Exploring
Related pages for recurring billing and supporter flows
Subscriptions do not live in isolation. These adjacent pages help buyers evaluate the broader payment model around recurring billing.
const plan = await flint.subscriptionPlans.create({name: "Pro Monthly",billingInterval: "MONTHLY",lineItems: [{name: "Pro seat",unitPriceMoney: { amount: 4900 },}],});const sub = await flint.subscriptions.create({customerId: "cus_01HZ4X8",planId: plan.id,paymentMethodId: "pm_01HZ8K4",});// sub.status → "TRIALING"// Billing starts automatically.