The short answer on Flint
Flint invoices carry payment terms with a late fee policy: a fixed amount or a percentage, a grace period, and either automatic or manual assessment. When the due date passes with a balance left, Flint marks the invoice overdue, sends the reminders you scheduled, and after the grace period adds the fee to the same invoice as a dated addendum. Nothing is voided, and the buyer pays the new balance from the link they already have. Card processing runs on Stripe underneath. The Flint requests are below.
What a Stripe invoice does after its due date
A Stripe invoice has five statuses: draft, open, paid, void, and uncollectible. Passing due_date changes none of them. The invoice object has due_date and amount_remaining and no field for a late fee or a fee policy.
What Stripe does give you around the due date:
- Reminder emails, configured in Billing settings to go before, on, or after the due date.
- An
invoice.overdue webhook, sent the number of days after the due date that you set in a Billing automation with the Invoice is overdue trigger, for invoices sent to the customer to pay. - Automation actions: mark the invoice uncollectible, email your team, or change a subscription. None of them adds a charge to the invoice.
So the fee is yours to compute and add. Most details of a finalized invoice, including its amounts, can't be updated, which leaves two ways to put a fee in front of the customer.
The workaround: revise the invoice from a webhook
Revising creates a new draft linked to the original with the same line items. Add the fee as an invoice item, then finalize the revision, which voids the original:
// invoice.overdue arrives X days after the due date; X is set in a
// Billing automation with the "Invoice is overdue" trigger.
if (event.type === "invoice.overdue") {
const original = event.data.object;
if (await db.lateFees.existsFor(original.id)) return res.sendStatus(200);
const fee = Math.round(original.amount_remaining * 0.015); // your policy: 1.5%
// A finalized invoice's amounts can't change, so revise it
const revision = await stripe.invoices.create({
from_invoice: { invoice: original.id, action: "revision" },
});
await stripe.invoiceItems.create({
customer: original.customer,
invoice: revision.id,
amount: fee,
currency: original.currency,
description: "Late fee: 1.5% of the unpaid balance",
});
await db.lateFees.insert({ original: original.id, revision: revision.id, fee });
await stripe.invoices.finalizeInvoice(revision.id); // voids the original
await stripe.invoices.sendInvoice(revision.id);
}
res.sendStatus(200);
The other route is a separate invoice holding only the fee. It leaves the original alone, and the customer gets two bills for one late payment. Either way, the grace period, the percentage, the once-only rule, and the waiver when a good customer calls are code and records you keep. These are the places that code breaks:
Where hand-built late fees go wrong
On Flint, the late fee is part of the payment terms
A payment term says when an invoice is due and what happens after. This one is Net 30 with a 1.5% fee, ten days of grace, and automatic assessment:
curl -X POST https://api.withflintpay.com/v1/invoice-payment-terms \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: term-net30-late-fee" \
-H "Content-Type: application/json" \
-d '{
"name": "Net 30, 1.5% late fee",
"calculation": { "type": "net_days", "days": 30 },
"late_fee_policy": {
"type": "percentage",
"percent": 1.5,
"grace_period_days": 10,
"application_mode": "automatic"
}
}'
A fixed fee uses "type": "fixed" with amount_money instead of percent. Point an invoice at the term with payment_due:
curl -X POST https://api.withflintpay.com/v1/invoices \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: invoice-brand-refresh-001" \
-H "Content-Type: application/json" \
-d '{
"quick_pay": {
"customer_id": "cus_1kmn0aExample",
"line_items": [{
"name": "Brand refresh, phase 2",
"quantity": 1,
"unit_price_money": { "amount": 250000, "currency": "USD" },
"fulfillment": { "requirement": "none" }
}]
},
"collection": { "mode": "buyer_initiated" },
"payment_due": { "type": "payment_terms", "invoice_payment_term_id": "ipt_1kmn0aExample" },
"recipient_email": "ap@example.com"
}'
Or make the term your default and set the reminder schedule once for every invoice. Each reminder rule is an offset in days from the due date, negative for a heads-up before it, up to 20 rules:
curl -X PATCH https://api.withflintpay.com/v1/settings \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"invoices": {
"default_invoice_payment_term_id": "ipt_1kmn0aExample",
"reminder_policy": {
"rules": [
{ "days_from_due": -3 },
{ "days_from_due": 7 },
{ "days_from_due": 21 }
]
}
}
}'
Flint freezes the term, the fee policy, and the reminder schedule onto each invoice when you issue it, so a later settings change never rewrites a bill already sent. After issue, Flint does the follow-up:
- When the due date passes with a balance,
is_overdue turns true and Flint sends invoice.overdue. - Reminders go out on your schedule, with the invoice's current link.
- After the grace period, Flint sends
invoice.late_fee_due with the fee computed from the current balance. With automatic assessment it adds the fee, and when the invoice goes out by email, sends the buyer a fee notice.
{
"invoice_id": "inv_1kmn0aExample",
"due_at": "2026-08-01T00:00:00Z",
"base_outstanding_money": { "amount": 250000, "currency": "USD" },
"late_fee_money": { "amount": 3750, "currency": "USD" },
"late_fee_policy": { "type": "percentage", "percent": 1.5, "grace_period_days": 10 }
}
The fee raises the outstanding balance and shows as a dated addendum on the hosted invoice and the PDF. The issued line items, tax, and original total stay as they were, and the invoice keeps its number and link. Flint assesses once per invoice, or once per overdue installment on an invoice with a payment schedule, however many times you retry, and recalculates from the unpaid balance at that moment, so a payment that lands during the grace period lowers the fee.
With application_mode left at manual, the default, Flint sends you the invoice.late_fee_due event and emails the buyer nothing. One call assesses the fee. A fee assessed this way doesn't email the buyer or start a payment, so tell the customer yourself:
curl -X POST https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample/late-fees \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: late-fee-inv-1kmn0a-001" \
-H "Content-Type: application/json" \
-d '{}'
To forgive it, POST /v1/invoices/{invoice_id}/late-fees/{invoice_late_fee_id}/waive with a reason waives the unpaid remainder. Pause reminders on one invoice with reminders_paused when a customer promises a check. The policy is one fee per invoice or installment: Flint doesn't compound fees, repeat them monthly, or tax them. The invoicing guide covers installments, offline payments, and credit notes.
Who Flint is built for
US businesses billing customers in USD, such as agencies, consultants, wholesalers, and service companies, that want invoices, payment terms, reminders, and late fees on the same orders as the rest of their sales. See Flint invoices. Invoices are an add-on at 0.40% of the payments collected through them, with no monthly fee.
Stripe and Flint invoices after the due date
| Stripe Invoicing | Flint invoices |
|---|
| Overdue state | Stays open; Past due badge in the Dashboard | is_overdue and an invoice.overdue event |
| Late fee policy | Your code and records | Fixed or percentage, with a grace period, on the payment term |
| Applying the fee | Revise the invoice, which voids the original, or bill a second invoice | Added to the same invoice, automatically or with one call |
| Fee assessed twice | Your job prevents it | Once per invoice or installment, enforced by Flint |
| Waiving a fee | Revise again or credit it | .../waive with a reason |
Questions, answered
Does Stripe support late fees on invoices?
Stripe's invoicing docs describe no late-fee setting, and the invoice object has no late-fee field. To charge one, you revise the open invoice to add a fee line, which voids the original and issues a replacement, or you bill the fee on a separate invoice.
Does a Stripe invoice become overdue?
Not as a status. An unpaid invoice stays open after its due date; the Dashboard shows a Past due badge on it. If you set up a Billing automation with the Invoice is overdue trigger, Stripe can send an invoice.overdue webhook a set number of days after the due date.
How do I add a late fee to a Stripe invoice automatically?
Listen for invoice.overdue, or run a daily job over open invoices past their due date. For each one, compute the fee from amount_remaining, create a revision with from_invoice, add the fee as an invoice item, finalize and send the revision, and record the fee so it is never added twice.
Can Stripe automations add a late fee?
Not directly. The actions Stripe lists for automations are retry policies, subscription status changes, marking an invoice uncollectible, emails, and a webhook. None adds a charge, so the fee itself is code you run when the webhook arrives.
Which invoicing API supports late fees?
Flint invoices take payment terms with a late fee policy: a fixed amount or a percentage, a grace period, and manual or automatic assessment. Flint marks the invoice overdue, sends reminders on your schedule, and adds the fee to the same invoice as a dated addendum, without voiding it. Card processing runs on Stripe underneath.
Is Flint a good alternative to Stripe Invoicing?
Yes, for US businesses billing in USD that want payment terms, reminders, late fees, installments, and offline payments on invoices backed by orders. Invoices are an add-on at 0.40% of payments collected through them, on top of Flint's published card rate of 3.79% + 35¢, which covers Stripe's processing fees, with no monthly fee.
Sources
All sources accessed October 15, 2026.