How to charge a late fee on a Stripe invoice

Stripe's invoicing docs describe no late-fee setting, and an unpaid invoice has no overdue status: it stays open past its due date, with a Past due badge in the Dashboard. To charge a fee, you revise the invoice to add a fee line, which voids the original and issues a replacement, or you bill the fee on a second invoice. Your own job decides when, from a webhook or a schedule.
Verified against official documentationReviewed Send a correction (opens in a new tab)

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:

JavaScript
// 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

  1. Adding the fee voids the invoice your customer already has#

    Accounts payable paid the original link and got told the invoice was void.

    A finalized invoice's amounts can't be updated. Revising it creates a new draft linked to the original, and finalizing that draft voids the original. Every link and PDF you sent before the fee now points at a void invoice.

    Confirm it

    Open an original invoice after a fee was added. Its status is void and latest_revision names the replacement.

    Fix

    Send the revised invoice with a message that says why it replaced the first one, and update any invoice IDs or links stored in your own system.

  2. Some overdue invoices can't be revised at all#

    Your late-fee job fails with a 400 on a subscription invoice, or on one with a credit note.

    Stripe won't revise invoices attached to subscriptions, invoices with a credit note, or invoices with a payment in processing, such as a bank debit that hasn't cleared, and an invoice can have only one draft revision at a time. The exception is a private preview: open invoices from subscriptions on flexible billing mode can be edited.

    Confirm it

    Log every 400 from your revision call with the invoice ID and look for these cases.

    Fix

    For those invoices, bill the fee on a separate invoice, or let the fee wait until the processing payment settles. The customer then has two balances to pay, so link them in the memo.

  3. The fee gets added twice#

    A customer was charged 1.5% on top of 1.5%.

    Webhooks can arrive more than once, and a revision is a new invoice with a new ID. If your job keys on the invoice ID it received, the revision looks like a fresh overdue invoice the next time the job runs.

    Confirm it

    Search for invoices with two late-fee items, or for a revision chain longer than one link.

    Fix

    Record each fee against the original invoice ID in your database before you create the revision, and skip any invoice whose from_invoice chain already has a fee.

  4. The fee is computed on money that already arrived#

    A customer who paid half on time was charged a fee on the full amount.

    A percentage fee needs the balance at the moment you assess it. If you compute it from the invoice total instead of amount_remaining, or compute it before a payment that is still settling, the fee is too large.

    Confirm it

    Compare each fee with 1.5% of amount_remaining at the time the fee was added.

    Fix

    Compute the fee from amount_remaining immediately before you add it, and skip invoices with a payment in processing.

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

  1. When the due date passes with a balance, is_overdue turns true and Flint sends invoice.overdue.
  2. Reminders go out on your schedule, with the invoice's current link.
  3. 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.
JSON
{
  "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
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 InvoicingFlint invoices
Overdue stateStays open; Past due badge in the Dashboardis_overdue and an invoice.overdue event
Late fee policyYour code and recordsFixed or percentage, with a grace period, on the payment term
Applying the feeRevise the invoice, which voids the original, or bill a second invoiceAdded to the same invoice, automatically or with one call
Fee assessed twiceYour job prevents itOnce per invoice or installment, enforced by Flint
Waiving a feeRevise 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.