Stripe alternative
The real Stripe comparison is charge-first vs. order-first
Stripe is strong at processing cards. The break happens after the charge, when your team still needs one source of truth for line items, discounts, tax, refunds, invoices, hosted checkout, payment links, subscriptions, and support history.
You build and maintain the commerce layer.
Line items, tax, discounts, payments, refunds, activity trail. One record.
What This Page Answers
Should we keep Stripe and fix the layer above it, or replace the whole stack?
If card processing is fine but order state, refunds, checkout context, and support history are what hurt, the real decision is charge-first versus order-first, not Stripe versus non-Stripe.
Many teams misdiagnose the pain as processor choice when the real issue is that the processor charge object is carrying too much business responsibility.
Architecture Shift
The processor can stay the same while the system boundary changes
The real migration is not from one payment rail to another. It is from a charge object that carries too much responsibility to an order model that carries the business state cleanly.
The processor charge succeeds, but the surrounding business state still lives in your app.
The processor stays in place. The durable record and operational history move into the order model.
Charge-first works early. The pain shows up in the layer above the charge.
The first successful payment is not the hard part. Day one with Stripe is great. You create a PaymentIntent, it works, you ship. Then the real requirements arrive.
Line items with quantities and prices. Tax calculations that update when discounts apply. Partial refunds that need to reconcile against the original order. Coupons. Tips. Subscriptions. Support needs to look up what was actually purchased, not just the amount that was charged.
So you build an orders table. Then a line items table. Then a refunds ledger. Then a webhook handler that tracks payment state transitions. Six months later you have 2,000+ lines of commerce glue code that sits between your application and a payment API that only understands one thing: charge a number.
Flint takes the opposite approach. The order is the primitive. Payments, refunds, tax, coupons, and subscriptions are operations on that order. You do not build a commerce layer. It is the API.
Where Charge-First Breaks
The failure modes are operational, not theoretical
Teams usually do not switch because card charging fails. They switch because the business logic around the charge keeps fragmenting.
Refunds become repair work
A refund succeeds at the processor, but support and finance still need you to reconstruct what changed in the order record.
Hosted surfaces split the business record
Checkout sessions, links, and billing flows drift into separate states that your app must stitch back together after payment succeeds.
Support reads multiple truths
Operators end up checking processor events, your database, and webhook logs to answer a simple question about what happened.
See the difference
Stripe returns a payment object. Flint returns a commerce record.
That is the actual divide. Payment processors tell you whether money moved. Order-first systems tell you what was sold, how totals were derived, what changed later, and what can happen next.
const paymentIntent = await stripe.paymentIntents.create({amount: 6384,currency: "usd",metadata: { order_id: "internal_1042" },});// Stripe now knows charge state.// Your app still owns:// - line items// - discounts// - tax math// - refund allocation// - customer-facing order history
const order = await flint.orders.create({line_items: [{ name: "Coffee Beans", quantity: 2,unit_price_money: { amount: 1999, currency: "USD" } },{ name: "Pour-Over Mug", quantity: 1,unit_price_money: { amount: 2400, currency: "USD" } },],discounts: [{ coupon: { coupon_code: "WELCOME10" } }],});// Flint computes totals and keeps the record:// order.pricing_amounts + order.settlement_amounts → subtotal, discount, tax, paid, refunded, outstanding// order.activities → every state change// order.payment_intent_ids, refund_ids, checkout_session_ids
Comparison
What actually changes when you move from charge-first to order-first
The practical difference after launch, not the difference in a headline.
| Capability | Stripe | Flint |
|---|---|---|
System of record Which object the business trusts | PaymentIntent + your own order database | Order is the primary record |
Computed totals Subtotal, discount, tax, paid, refunded, balance | You assemble this around the charge | Built into order.pricing_amounts and order.settlement_amounts |
Refund workflow What happens after money is returned | Refund raw amount, reconcile state yourself | Refund stays linked to the order record |
Hosted flows Checkout sessions and payment links | Separate surfaces, less shared context | Order-backed checkout and payment links |
Subscription linkage How billing connects to the sale | Billing sits adjacent to order context | Subscription lineage stays on the order |
Operational history What support and finance read later | Processor events + your own tables | Order activities + linked payment and refund IDs |
Agent readability How easy it is for AI to reason about | Opaque amounts and statuses | Structured data + explicit next actions |
Stripe remains a strong processor. Flint changes what sits above the processor by making the order, not the charge, the durable record.
Refund example
The refund stays inside the order workflow
Flint's public refund API is still amount-based, but the result remains attached to the order instead of becoming a disconnected processor event you reconcile later.
// Query your own order storeconst order = await db.orders.findById(orderId);// Reconstruct what should be refundedconst subtotal = getRefundableSubtotal(order, returnedItems);const tax = recalculateTaxShare(order, returnedItems);// Refund a raw amountawait stripe.refunds.create({payment_intent: order.stripePaymentIntentId,amount: subtotal + tax,});// Then repair your own stateawait db.orders.update(orderId, {refundedAmount: order.refundedAmount + subtotal + tax,status: "partially_refunded",});
const refund = await flint.refunds.create({order_id: "ord_01JY...",amount_money: { amount: 2900, currency: "USD" },reason: "REFUND_REASON_REQUESTED_BY_CUSTOMER",idempotency_key: "refund-support-2900",});// Refund lives on the order record.// order.refund_ids now includes refund.refund_id.// order.settlement_amounts.refunded_money updates.// order.status can move to PARTIALLY_REFUNDED.
What Flint Replaces
The surface area that stops living in glue code
The order-first difference is not one endpoint. It is the set of connected objects and flows that stop being your application's problem.
orders
Order record
What was sold, how totals were computed, and what changed later all live on one durable business record.
payment_intents
Processor-backed payments
Stripe still handles the card rails while Flint stops the charge object from carrying your whole commerce model.
refunds
Refund linkage
Refunds stay attached to the order and update balances, activities, and support history without repair work.
checkout_sessions
Hosted checkout
Hosted payment flows inherit order context instead of fragmenting state into another standalone payment surface.
When This Matters
Flint is the better fit when the problem is above the rail
This page should help a team separate processor choice from commerce-model choice.
Use This When
Choose Something Else When
SaaS platform with internal support tooling
Support needs to answer what was purchased, what changed later, and what can still happen next without correlating processor events manually.
Commerce flow with multiple collection surfaces
Hosted checkout, payment links, invoices, and subscriptions should all stay tied to the same order record instead of splintering state.
Stripe still processes every card
This is not a pitch to give up Stripe's payment infrastructure. Card data goes to Stripe directly. Flint never sees or stores card numbers. You get the same PCI scope, the same fraud detection, and the same dispute handling you would get with a direct Stripe integration.
Flint adds the commerce layer on top: orders, line items, computed totals, automatic state transitions, coupons, tax, and refund reconciliation. The hard parts that every team ends up building themselves.
Migration
Migrate from Stripe without changing the processor
The shape of the integration stays familiar. The important change is where the business truth lives.
Connect your existing Stripe account
Keep Stripe as the processor. Flint uses it for card movement while replacing the commerce state you would otherwise build yourself.
Replace charge creation with order creation
Start from orders.create with real line items and customer context, then derive payment collection from that record.
Move hosted checkout and links onto the order model
Create checkout sessions or payment links that remain tied to the order instead of letting hosted flows fragment your state.
Issue refunds against the order workflow
Refunds target the order or payment intent while staying attached to the order record. No manual reconciliation.
Swap webhook handlers to order-aware events
Consume richer order, refund, and checkout context instead of treating processor events as the full business truth.
Implementation
Go straight to the docs if you want to test the model
This page should narrow the decision. The docs should prove it.
Operator View
The day-two operational surface is where the model difference shows up
These are the places teams usually feel the pain first once charge-first abstractions stop being enough.
Support
Support reads one record instead of correlating events
A support tool can start from the order and see payment IDs, refund history, totals, and next actions without stitching together processor dashboards and internal tables.
Migration
Your integration surface stays familiar
You are not replacing card collection or losing Stripe's processor behavior. You are moving the business truth into a model that can drive operations cleanly.
// Keep Stripe as the processor.// Replace charge creation with order creation.// Move hosted flows and refunds onto the order record.// Let support and automation read one semantic object.
Frequently asked questions
Choose The Right Model
Which direction should your team take from here?
The next step depends on whether you are evaluating architecture, implementation, or rollout strategy.
You believe the business pain is really order-state fragmentation
Read Payment API
Move from the conceptual comparison into Flint's core order-backed payment model.
Read Commerce API
Take the broader path when orders, catalog, refunds, and billing all need one product surface.
Read the Orders API
Skip the marketing layer and inspect the object model directly in the docs.
Keep Exploring
Related pages for the charge-first versus order-first decision
If this page captures the initial alternative intent, these are the next pages that deepen the product and workflow story.