Payment API for developers

Stop building order systems on top of payment APIs.

You've been there. The homegrown orders table. The manual total calculations. The webhook state machine that almost works. Flint is the order system - with payments, tax, coupons, invoices, refunds, subscriptions, and webhooks built in. Stripe processes the cards.

No credit cardFree sandbox forever5 min to first order
Without Flint
Cart DB
Stripe API
Tax Service
Inventory
Discount Logic
Refund Sync
Audit Log

You build all of this. You maintain all of this.

With Flint Pay
flint.orders.create()

Line items, tax, discounts, payments, refunds, audit trail. One call.

The problem

The payment-first integration trap

Day one with a payment API is great. You create a charge, it works, you ship. Then the 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.

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: amount: 3828

Every team that integrates a payment-first API ends up building the same thing - a homegrown order management system that the payment provider should have given them. You maintain it. You debug it at 2 a.m. You pray the ledger stays in sync.

Flint takes the opposite approach. The order is the primitive. Payments, refunds, tax, coupons, and subscriptions are operations on that order. You don't build a commerce layer - it's the API.

See the difference

Payment-first vs. order-first

Same feature. One approach requires you to build and maintain the commerce logic. The other gives it to you.

Typical payment API - you build the rest
// Calculate total yourself
const subtotal = items.reduce(
(sum, i) => sum + i.price * i.qty, 0
);
const tax = await taxService.calculate(subtotal);
const total = subtotal + tax;
// Charge a raw amount
const charge = await stripe.paymentIntents.create({
amount: total,
currency: "usd",
});
// Store in YOUR database
await db.orders.insert({
items, subtotal, tax, total,
stripeId: charge.id,
status: "paid",
});
// Later: manually reconcile refunds
const refund = await stripe.refunds.create({
payment_intent: charge.id,
amount: 2900,
});
await db.orders.update(orderId, {
refundedAmount: 2900,
status: "partially_refunded",
});
Flint - the API does it
// Create an order - totals computed
const order = await flint.orders.create({
lineItems: [
{ name: "Pro Plan", quantity: 1,
unitPriceMoney: { amount: 9900 } },
{ name: "Support Add-on", quantity: 1,
unitPriceMoney: { amount: 2900 } },
],
});
// order.netAmounts.totalMoney → 13824
// (subtotal + tax, auto-computed)
// Apply a coupon
await flint.orders.applyCoupon(order.orderId, {
couponCode: "LAUNCH20",
});
// Totals recomputed with discount + tax
// Pay - amount derived from order
await flint.orders.pay(order.orderId, {
paymentSourceTokens: ["tok_visa"],
});
// status → PAID. No manual calculation.
// Refund - state auto-transitions
await flint.refunds.create({
paymentIntentId: order.payments[0].id,
amountMoney: { amount: 2900, currency: "USD" },
reason: "requested_by_customer",
});
// status → PARTIALLY_REFUNDED. Done.

Left: you build the orders table, tax integration, and refund reconciliation. Right: the API handles it.

What you get

One integration, not six products

Orders, payments, catalog, billing, invoices, checkout, and real-time events. No separate services to stitch together.

Core

Orders

Create orders with structured line items, quantities, and prices. Totals, tax, and balances are computed automatically on every response.

Payments

Create payment intents from orders. Amount and currency are derived automatically. Stripe handles card processing under the hood.

Refunds

Issue full or partial refunds with one API call. The order balance, tax, and status recalculate automatically. No manual reconciliation.

Commerce

Items & Inventory

Define your product catalog with prices and track inventory. Attach items to orders by reference - no duplicate data.

Coupons & Discounts

Create percentage or fixed-amount coupons. Apply to orders and the discount flows through to computed totals automatically.

Tax

Tax is computed server-side on every order response. Amounts update automatically when line items, coupons, or tips change.

Customers

Store customer profiles with saved payment methods. Attach customers to orders for purchase history and repeat billing.

Billing

Subscription Plans

Define plans with recurring line items and billing intervals. Plans are templates - create once, subscribe many customers.

Subscriptions

Subscribe customers to plans with automatic invoicing and payment collection. Pause, resume, or cancel with one API call.

Distribution

Checkout Sessions

Generate a hosted checkout page from any order. Customers complete payment on a Flint-hosted page - no frontend form required.

Payment Links

Create shareable payment links that generate orders on click. Perfect for invoices, one-off charges, and event tickets.

Invoices

Send formal invoices when the buyer pays later or needs internal approval, without pushing billing into a separate system.

Webhooks

Receive real-time notifications for payment, order, and subscription events. Signed payloads with automatic retries.

How it works

From order to refund in five API calls

Create an order, apply a coupon, pay, refund a line item, and check the final state. Totals update and statuses transition automatically at every step.

1Create an order with line items
1-create-order.ts
const order = await flint.orders.create({
customerId: "cus_01HZ4X8",
lineItems: [
{
name: "Pro Plan - Annual",
quantity: 1,
unitPriceMoney: { amount: 9900, currency: "USD" },
},
{
name: "Priority Support Add-on",
quantity: 1,
unitPriceMoney: { amount: 2900, currency: "USD" },
},
],
});
// order.status → "OPEN"
// order.netAmounts.subtotalMoney → { amount: 12800 }
// order.netAmounts.taxMoney → { amount: 1024 }
// order.netAmounts.totalMoney → { amount: 13824 }
// order.netAmounts.balanceMoney → { amount: 13824 }
2Apply a coupon - totals recompute automatically
2-apply-coupon.ts
const updated = await flint.orders.applyCoupon("ord_01HZ4X9", {
couponCode: "LAUNCH20",
});
// 20% off applied. Server recomputed everything:
// updated.netAmounts.subtotalMoney → { amount: 12800 }
// updated.netAmounts.discountMoney → { amount: 2560 }
// updated.netAmounts.taxMoney → { amount: 819 }
// updated.netAmounts.totalMoney → { amount: 11059 }
// updated.netAmounts.balanceMoney → { amount: 11059 }
3Pay the order - amount derived automatically
3-pay-order.ts
const result = await flint.orders.pay("ord_01HZ4X9", {
paymentSourceTokens: ["tok_visa"],
buyerEmail: "alex@example.com",
});
// No amount specified - derived from order balance.
// Card charged via Stripe. Order status → PAID.
// result.order.netAmounts.paidMoney → { amount: 11059 }
// result.order.netAmounts.balanceMoney → { amount: 0 }
4Refund a line item - state transitions automatically
4-refund.ts
const refund = await flint.refunds.create({
paymentIntentId: "pi_01HZ4XA",
amountMoney: { amount: 2900, currency: "USD" },
reason: "requested_by_customer",
idempotencyKey: "refund-support-addon-01",
});
// Stripe processes the refund.
// Order status auto-transitions → partially_refunded.
// refund.status → "pending"
5Check the final state - everything reconciled
5-final-state.ts
const order = await flint.orders.get("ord_01HZ4X9");
// order.status → "partially_refunded"
// order.netAmounts.totalMoney → { amount: 11059 }
// order.netAmounts.paidMoney → { amount: 11059 }
// order.netAmounts.refundedMoney → { amount: 2900 }
// order.netAmounts.balanceMoney → { amount: 0 }
// No manual reconciliation. No webhook state machine.

Comparison

Flint vs. traditional payment APIs

What you get out of the box with Flint versus what you build yourself on top of a payment-first API.

CapabilityPayment-firstFlint Pay
Order management
Line items, quantities, prices
Build from scratch
Built-in order object
Totals & balances
Auto-computed net amounts
Calculate yourself
Computed on every response
Tax calculation
Compute per-item tax
Build or buy separately
Built-in, per line item
Discounts & coupons
Apply, stack, enforce limits
Build from scratch
Built-in with stacking rules
Refund handling
Refund and recalculate
Multi-step across systems
One call, auto-reconciled
State machine
Deterministic lifecycle
Build from scratch
OPEN → PAID → CLOSED
Subscription billing
Plans, trials, retries
Cron jobs + state machine
Auto-billing with lifecycle
AI agent support
Structured data for LLMs
Not possible
Semantic responses + /SKILL.md

Why Flint

Built different, on purpose

A payment API should do more than move money. It should understand what you sell and handle the complexity for you.

Order-first, not payment-first

The order is the primitive. Payments, refunds, coupons, and tax attach to it. You never build an orders table or reconcile across systems.

Server-computed totals

Subtotals, tax, discounts, balances, and refunded amounts are computed on every response. You never calculate a total or maintain a ledger.

Automatic state transitions

Pay an order - status moves to PAID. Refund part of it - PARTIALLY_REFUNDED. Refund the rest - REFUNDED. No webhooks to poll, no state to reconcile.

Idempotent by design

Every mutating endpoint accepts an idempotency key. Safe retries, safe webhooks, safe AI agents. No duplicate charges, no double refunds.

Stripe processes every card

Card data goes directly to Stripe. Same PCI scope, same fraud detection, same dispute handling. Flint adds the commerce layer on top.

AI-ready responses

Responses include line item names, available actions, and deterministic statuses. AI agents can reason about orders without parsing opaque amounts.

Lifecycle

Deterministic order status machine

Every order follows a predictable lifecycle. Transitions are enforced server-side - no ambiguous states, no manual bookkeeping.

OPENPAIDPARTIALLY_REFUNDEDREFUNDED
or
PAIDCLOSED
OPENOrder is mutable. Add line items, apply coupons, add tips. All amounts recompute on every change.
PAIDPayment captured. Only refunds and metadata updates are allowed.
PARTIALLY_REFUNDEDSome amount refunded. Balance, tax, and totals recalculated. Further refunds still allowed.
REFUNDEDFully refunded. Balance is zero. No further mutations allowed.
CLOSEDSettled and archived. Terminal state for completed transactions.

Trust & security

Stripe handles every card

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'd 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.

payment-flow.json
{
"flow": [
"Your app → Flint API (order + line items)",
"Flint → Stripe (card charge, PCI-scoped)",
"Stripe → Flint (payment confirmed)",
"Flint → Your app (order status: PAID)"
],
"cardDataTouches": ["Stripe"],
"pciScope": "SAQ-A (same as direct Stripe)",
"fraudDetection": "Stripe Radar (included)"
}
// Flint never touches card data.
// Same security. Better commerce.

Get started

Ship commerce, not glue code.

Orders, payments, tax, coupons, subscriptions, refunds, and webhooks. One API. Stripe processes the cards. Free to start.

No credit card requiredFree sandbox foreverProduction ready in minutes
quickstart.ts
const order = await flint.orders.create({
lineItems: [{
name: "Pro Plan - Annual",
quantity: 1,
unitPriceMoney: { amount: 9900 },
}],
});
const result = await flint.orders.pay({
orderId: order.id,
paymentSourceTokens: ["tok_visa"],
});
// order.status → "PAID"
// Total, tax, balance: all computed.