Headless commerce infrastructure for developers

Commerce first.Keep the order.

Payment APIs push commerce complexity onto your app. Flint keeps payments, checkout, refunds, and subscriptions connected through the same order model.

Start with one payment callAdd orders, checkout, refunds, and subscriptions laterFree sandbox, no credit cardTypeScript, Python, and Go SDKs
One order-centered API
same record
payments.ts
const intent = await flint.paymentIntents.create({
amountMoney: { amount: 2500, currency: "USD" },
paymentSourceToken: "pm_1Qs2...x4B",
autoConfirm: true,
})
// intent.status === "SUCCEEDED"
// Start simple. No order required.
Use Flint like a payment API on day one. Add more structure later without switching platforms.

Compare

Payment acceptance is not the hard part.

The hard part starts after the charge: what was bought, how totals were computed, what changed, and how a refund maps back to the buyer experience. That is where payment primitives stop being enough.

Stripe + your code
3 moving parts
1. Rebuild your cart state
cart.ts
1const cart = await db.cart.findUnique({
2 where: { id: cartId },
3 include: { items: true, customer: true },
4})
5
6if (!cart) throw new Error("Cart not found")
2. Compute what Stripe does not know
totals.ts
1const subtotal = cart.items.reduce(
2 (sum, item) => sum + item.price * item.qty, 0
3)
4const tax = await taxService.calculate({
5 amount: subtotal,
6 address: cart.customer.address,
7})
3. Stitch checkout back to your order
webhook.ts
1const session = await stripe.checkout.sessions.create({
2 line_items: cart.items.map(toLineItem),
3})
4
5app.post("/webhook", async (req, res) => {
6 // update your order, coupon usage, and status
7})
Cart state, totals logic, and webhook reconciliation live in your app.
Flint
2 direct calls
1. Create the order
order.ts
1const order = await flint.orders.create({
2 lineItems: [
3 { name: "Cold Brew", quantity: 2,
4 unitPriceMoney: { amount: 650, currency: "USD" } },
5 { name: "Croissant", quantity: 1,
6 unitPriceMoney: { amount: 495, currency: "USD" } },
7 ],
8})
2. Attach checkout
checkout.ts
1const checkout = await flint.checkoutSessions.create({
2 orderId: order.orderId,
3 redirects: {
4 successRedirectUrl: "https://app.example/success",
5 cancelRedirectUrl: "https://app.example/cart",
6 },
7})
The order stays readable from create to checkout to refund.
State model
Your DB + Stripe
One order record
Refund logic
Per charge
Against the order
Tax & totals
You calculate
Computed for you
Checkout sync
Webhook glue
Native lifecycle

Why Teams Switch

The rewrite usually starts with edge cases.

Most teams do not replace their payment stack because the first charge fails. They replace it when support, reconciliation, and new buyer flows make the old model too expensive to keep together.

Cart state drifts from payment state

Line items, tax, discounts, and buyer context live in your app, while the charge lives somewhere else.

Flint keeps the order, checkout, and payment state on one record your team can actually read.

Refunds turn into manual reconciliation

Support has to reconcile what the buyer bought, what they paid, and what got refunded across multiple systems.

Refunds attach to the same order record and activity trail instead of becoming isolated money movement.

New flows create a second model

Checkout, subscriptions, and future buyer workflows add more objects, webhooks, and sync logic to maintain.

Flint keeps new flows on the same API and order model instead of forcing a later rewrite.

Start simple. Grow without rewrites.

Adopt the order only when the product needs it.

Use Flint like a payment API on day one. The moment the product needs line items, checkout, refunds, or subscriptions, you keep building on the same model instead of introducing a second system.

Start simple

Take a payment and move on.

If all you need is to charge a customer, Flint lets you do exactly that. One call. No order required. No forced complexity.

Same auth and API keysSame order modelAdopt only what you need
Just payments
flint.ts
const intent = await flint.paymentIntents.create({
amountMoney: { amount: 2500, currency: "USD" },
paymentSourceToken: "pm_1Qs2...x4B",
autoConfirm: true,
})
// intent.status === "SUCCEEDED"

Real Workflow Example

One buyer flow. One order record.

The point is not that Flint can create a charge. The point is that the same record stays readable when the buyer pays, support steps in, and the product later grows onto the same order model.

01

Create the order once

Your app creates one order with line items, totals, buyer context, and the exact thing being sold before money moves.

02

Attach checkout and get paid

The buyer completes checkout, and the payment lands back on that same order instead of becoming a disconnected charge.

03

Handle the support moment

If the buyer needs a refund or a status explanation, support can act against the order instead of reconciling multiple systems.

04

Add the next workflow later

When the product expands into subscriptions or other commerce flows, it builds on the same order model instead of introducing a second system.

Buyer context
What they bought, paid for, and refunded stays connected
Support context
Operators act against the order instead of reconciling systems
Growth context
New commerce flows build on the same model, not a new stack

Recurring Billing

Subscription billing stays closer to what you actually sell.

Flint keeps recurring billing on top of the same order model. Multiple line items, trial terms, and lifecycle rules can live together instead of getting split across billing primitives.

Stripe Billing
more objects
const baseProduct = await stripe.products.create({
name: "Pro Platform",
})
const basePrice = await stripe.prices.create({
product: baseProduct.id,
recurring: { interval: "month" },
})
const seatsProduct = await stripe.products.create({
name: "Team Seats",
})
const seatsPrice = await stripe.prices.create({
product: seatsProduct.id,
recurring: { interval: "month" },
})
const sub = await stripe.subscriptions.create({
customer: "cus_xxx",
items: [
{ price: basePrice.id },
{ price: seatsPrice.id, quantity: 5 },
],
})
Products, prices, and subscription state get split across multiple primitives.
Flint
one model
const plan = await flint.subscriptionPlans.create({
name: "Pro Platform + Seats",
lineItems: [
{ name: "Base platform",
unitPriceMoney: { amount: 4900, currency: "USD" },
quantity: 1 },
{ name: "Team seats",
unitPriceMoney: { amount: 1800, currency: "USD" },
quantity: 5 },
],
billingInterval: "monthly",
trialPeriodDays: 14,
})
const sub = await flint.subscriptions.create({
planId: plan.planId,
customerId: "cus_01HZ4X...",
})
Plan structure, trial terms, and subscription lifecycle stay on one platform surface.
Plan shape
Multiple recurring line items on one plan
Billing terms
Trials and plan rules without extra object choreography
Why it reads better
The subscription stays closer to the business model

Developer Fit

Why teams keep this in production.

Teams do not just buy features. They buy systems they can trust under retries, refunds, support workflows, and product change.

API-first, not dashboard-first

The core model is available directly in the API and SDKs. The dashboard helps you operate it; it is not where the real system lives.

Less schema you own

You do not need to build and maintain separate cart, totals, coupon, and reconciliation tables before you can ship.

Operational safety

Deterministic statuses and explicit lifecycle state make retries, webhooks, refunds, and support flows easier to reason about.

Grows without a rewrite

Start with payments if you want. Add orders, checkout, refunds, and subscriptions later on the same API instead of rebuilding around a new model.

AI

The same order model is easier for agents and internal tools.

Flint returns explicit order, refund, and lifecycle state, plus method hints for side effects. Agents and support tools do better when they do not have to infer business context from raw charges.

Method hints on the API surface
operation_typeCREATE
side_effect_levelFINANCIAL
requires_human_confirmationtrue
terminal_states["SUCCEEDED","FAILED"]
Order-aware agent execution
"Refund Sarah's coffee beans from her last order"
Reading schema hints for CreateRefund...
Found order ord_01HZ4X9 with refundable line item.
This moves money. Confirm refund of $39.98?

Pricing

Start free. Move up when you need more.

Start in the sandbox, ship the first integration, and move to paid plans when you want lower fees, reporting, and production support.

Build
Free
3.6% + 35¢ per transaction

For side projects, prototypes, and getting your first integration live.

Recommended for teams shipping to production
Growth
$399/mo
2.9% + 30¢ per transaction

For teams that want lower fees, more reporting, and priority support.

Enterprise
Custom
Volume pricing

For platforms that need a custom fee model and deeper partnership.

Start Building

Start with one payment call. Keep the same order model.

Ship the simple flow first. When you need orders, checkout, refunds, or subscriptions, they build on the same API and order model you started with.