Invoices
Send it once. Flint does the chasing.
One call turns line items, or an order you already have, into an invoice. Issue it and Flint numbers it, freezes the document, and emails a hosted page that takes cards, Apple Pay, Google Pay, Affirm, and bank debit. Then it reminds on your cadence, flags the invoice overdue, raises the late fee, and retries a saved card. The check that arrives by mail records against the same balance, so what is still owed is a field you read, not a spreadsheet you keep.
What happened to INV-0231
The link, if you want to send it yourself
Issue returns it. Flint emails it for you, or you drop it into your own message. Every reminder carries it, and it can be rotated in one call if it leaks.
5
ways to pay on the hosted page
payment_policy.enabled_payment_options
4
follow-up jobs Flint runs after issue
reminders, overdue, late fee, saved-card retries
11
filters on the receivables report
GET /v1/invoices
25
invoice events on your webhook
webhook event catalog
01Collect
Every way to pay, on a page you did not build.
The hosted page takes cards, Apple Pay, Google Pay, Affirm, and ACH debit, and you pick the set per invoice. Cap cards above an amount and the big invoices pay by bank. Turn on the cost comparison and the page tells the buyer what bank debit saves. Or skip the page: charge the card on file, or record what arrived some other way.
{
"collection": {
"mode": "buyer_initiated",
"payment_policy": {
"enabled_payment_options": [
"card",
"apple_pay",
"google_pay",
"affirm",
"ach_debit"
],
"payment_option_limits": [
{
"payment_option": "card",
"max_total_money": { "amount": 500000, "currency": "USD" }
}
],
"show_cost_comparison": true
}
}
}Frozen onto the invoice at issue, so a settings change later never alters a receivable already out. A card cap at $5,000 hides card on the $6,000 invoice and leaves bank debit.
The payment options a policy can name
- card
- apple_pay
- google_pay
- affirm
- ach_debit
Bank debit that is still processing shows the buyer the expected settlement date on the page, and only one payment attempt can be live on an invoice at a time, across every rail. Every attempt, including a decline, is a record you can list.
- payment_policy.enabled_payment_options
- payment_option_limits
- show_cost_comparison
- POST /v1/invoices/{invoice_id}/collect
- POST /v1/invoices/{invoice_id}/manual-payments
02Terms
Net 30, a deposit, and two installments. Say it once.
A payment term is a resource: due on receipt, net days, a day of the month, or days after month end, with a late fee policy attached. Put it on an invoice and the due date, the terms line on the document, and the late fee notice all follow from it. A schedule splits one invoice into a deposit, installments, and a balance, and the hosted page asks for what is due now.
curl -X POST https://api.withflintpay.com/v1/invoice-payment-terms \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"name": "Net 30",
"calculation": { "type": "net_days", "days": 30 },
"late_fee_policy": {
"type": "percentage",
"percent": 1.5,
"grace_period_days": 10
}
}'Reference it from an invoice, or set it as the default in your settings and never mention it again. Every invoice on it prints the term and the fee on the document.
{
"order_id": "ord_2bqr7dExample",
"payment_due": {
"type": "payment_terms",
"invoice_payment_term_id": "ipt_1kmn0aExample"
},
"schedule_entries": [
{
"kind": "deposit",
"amount_specification": { "type": "percentage", "percent": 50 },
"due": { "type": "at_issue" }
},
{
"kind": "installment",
"amount_specification": {
"type": "fixed",
"amount_money": { "amount": 150000, "currency": "USD" }
},
"due": { "type": "date", "due_at": "2026-08-20T00:00:00Z" }
},
{
"kind": "balance",
"amount_specification": { "type": "remaining_balance" },
"due": { "type": "invoice_due_date" }
}
]
}A deposit, installments, and a balance, each a fixed amount, a percentage, or the remainder, up to 14 entries. Leave the array out and the invoice is due in one payment on its terms.
{
"invoice_number": "INV-0226",
"status": "partially_paid",
"outstanding_money": { "amount": 150000, "currency": "USD" },
"currently_due_money": { "amount": 150000, "currency": "USD" },
"schedule_entries": [
{
"kind": "deposit",
"status": "satisfied",
"total_money": { "amount": 300000, "currency": "USD" }
},
{
"kind": "installment",
"status": "satisfied",
"total_money": { "amount": 150000, "currency": "USD" }
},
{
"kind": "balance",
"status": "overdue",
"total_money": { "amount": 150000, "currency": "USD" },
"outstanding_money": { "amount": 150000, "currency": "USD" }
}
]
}The hosted page and the cost line work from the amount due now, not the whole balance, so a customer paying the deposit sees the deposit.
How a term computes its due date
- on_receipt
- net_days
- day_of_month
- day_of_next_month
- days_after_month_end
- POST /v1/invoice-payment-terms
- late_fee_policy
- schedule_entries
- currently_due_money
03Follow-up
Issue it and walk away.
Issuing an invoice schedules its follow-up. While a balance remains, Flint sends reminders on the day offsets you set, marks the invoice overdue, raises the late fee notice once the grace period passes, and retries a saved card on your schedule. A payment that lands first cancels the rest. When the customer replies, pause the cadence with one call.
curl -X PATCH https://api.withflintpay.com/v1/settings \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"invoices": {
"reminder_policy": {
"rules": [
{ "days_from_due": -3 },
{ "days_from_due": 7 },
{ "days_from_due": 21 }
]
},
"autopay_retry_policy": { "retry_day_offsets": [3, 5, 7] },
"default_invoice_payment_term_id": "ipt_1kmn0aExample"
}
}'Offsets from the due date, negative ones before it. Frozen onto each invoice at issue, so editing the settings changes the invoices you issue from then on and leaves the ones in flight alone. The retry offsets apply to saved-card invoices, counted from the decline.
# they replied and promised a check; stop the cadence, keep the record
curl -X PATCH https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: pause-invoice-north-street-2026-07" \
-d '{ "reminders_paused": true }'Stops the automatic reminders on that invoice and stamps when. Setting it back to false resumes them, and a one-off reminder still sends while paused.
# write it today, let Flint issue and email it on the first
curl -X PATCH https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{ "scheduled_send_at": "2026-10-01T13:00:00Z" }'Flint issues and emails the draft at that moment, and the follow-up starts from there. Clear it to cancel.
What each job runs on
- Reminders
- Day offsets from due, sent by Flint with the link
- Overdue
- The due date passing with a balance remaining
- Late fee
- The grace period on the invoice's payment term
- Retries
- Day offsets from a saved-card decline
- reminder_policy
- autopay_retry_policy
- scheduled_send_at
- reminders_paused
- POST /v1/invoices/{invoice_id}/send-reminder
04The balance
Card, bank, check, cash. One number.
The hosted page collects what is due. Whatever arrives another way, you record against the same invoice, and the same three fields move. A check that bounces reverses back out, and the status follows the money in both directions.
# the check that arrived by mail
curl -X POST \
https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample/manual-payments \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: check-4417" \
-d '{
"amount_money": { "amount": 80000, "currency": "USD" },
"received_at": "2026-08-12T00:00:00Z",
"external_reference_id": "4417",
"note": "Check, deposited Aug 13"
}'Any positive amount up to the balance, backdated to the day it arrived, with the check number kept on the record. This is where a partly paid invoice comes from.
| one invoice, two rails | ||
|---|---|---|
| Invoice total, frozen at issuesnapshot | $1,836.00 | |
| Check 4417, recorded Aug 12POST /v1/invoices/{invoice_id}/manual-payments | $800.00 | |
| Card ··4242, paid Aug 20POST /v1/invoices/{invoice_id}/checkout-session | $500.00 | |
| Paidpaid_money | $1,300.00 | |
| Outstandingoutstanding_money | $536.00 | |
{
"event_type": "invoice.manual_payment_recorded",
"data": {
"invoice_id": "inv_1kmn0aExample",
"invoice_number": "INV-0231",
"status": "paid",
"paid_money": { "amount": 183600, "currency": "USD" },
"outstanding_money": { "amount": 0, "currency": "USD" }
}
}A recorded payment that clears the balance arrives on the recorded-payment event with the new status on it. Every invoice event carries the post-event state, so one handler covers the check and the card without a follow-up fetch.
Why the number stays honest
The invoice owns collection on its order from issue until it closes, so nothing else can take a payment against that order behind its back. Card money and recorded money subtract from one frozen total, the status is computed from that total rather than set by hand, and refunds sit on their own axis. What the customer owes is one number because only one thing is allowed to change it.
- outstanding_money
- paid_money
- POST /v1/invoices/{invoice_id}/manual-payments/reverse
The rules, stated once
The page asks for the amount due, so a customer cannot pay a partial by hand, and you cannot be paid twice.
POST /v1/invoices/{invoice_id}/checkout-sessionRecording accepts any positive amount up to the balance, which is how an invoice becomes partly paid.
amount_moneyA reversal cannot exceed what was recorded, so card money is never quietly undone.
POST /v1/invoices/{invoice_id}/manual-payments/reverseA recorded payment that clears the balance closes any open checkout, so the hosted page can never collect twice.
invoice.manual_payment_recorded05Your side
The chase list is one query.
The invoice screen leads with the balance, the paid figure, and the actions left to take. The list filters the way the API does, so the aging report, biggest exposure first, is one call. And every send, reminder, and open is on the record for the day a customer says they never got it.
curl -G https://api.withflintpay.com/v1/invoices \
-H "Authorization: Bearer YOUR_API_KEY" \
-d has_amount_due=true \
-d sort_by=outstanding_money \
-d sort_direction=descEverything with a balance, sorted by what is owed. Add a customer, a due window, or your own reference to narrow it.
curl -G https://api.withflintpay.com/v1/invoices \
-H "Authorization: Bearer YOUR_API_KEY" \
-d is_overdue=true \
-d status=open,partially_paid \
-d sort_by=due_at \
-d sort_direction=ascPast due and still collectible, oldest first. Send a reminder to each, or let the cadence do it.
Every filter, and every sort key
- status
- customer_id
- order_id
- external_reference_id
- created_after
- created_before
- due_after
- due_before
- is_overdue
- has_amount_due
- query
- created_at
- updated_at
- due_at
- invoice_number
- outstanding_money
Unpaid and never arrived are different rows.
Every send and every reminder is a delivery attempt with an outcome, and the first time the customer opens the page stamps the invoice. A bounce fires its own event, so a receivables screen can flag it the hour it happens instead of a month later.
# the email was forwarded somewhere it should not have been
curl -X POST \
https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample/regenerate-public-link \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: regen-invoice-north-street-2026-07"The old link and any checkout credentials taken from it stop working immediately. A payment already in flight survives, and every reminder after this carries the new link.
{
"data": [
{
"invoice_delivery_attempt_id": "indel_1kmn0aExample",
"delivery_type": "send",
"channel": "email",
"to_email": "ap@northstreet.example",
"cc_emails": ["owner@northstreet.example"],
"status": "sent",
"sent_at": "2026-08-03T15:31:02Z"
},
{
"invoice_delivery_attempt_id": "indel_2bqr7dExample",
"delivery_type": "reminder",
"channel": "email",
"to_email": "ap@northstreet.example",
"status": "sent",
"sent_at": "2026-08-30T13:00:00Z"
},
{
"invoice_delivery_attempt_id": "indel_3fzt5xExample",
"delivery_type": "reminder",
"channel": "email",
"to_email": "ap@northstreet.example",
"status": "failed",
"error_message": "mailbox full"
}
]
}The third attempt failed and says why. The same news reaches your webhook endpoint as a delivery failure, so nothing polls.
And the whole story, in order
The invoice's own event log lists everything that happened to it: drafted, issued, sent, viewed, each payment, each reminder, each reversal, and who caused it. Support reads it instead of reconstructing it.
- GET /v1/invoices/{invoice_id}/delivery-attempts
- GET /v1/invoices/{invoice_id}/activities
- viewed_at
- POST /v1/invoices/{invoice_id}/regenerate-public-link
06Corrections
Fix a bill without a fight.
Two bags came back damaged. Credit the units and Flint works out their share of tax, numbers a credit note the customer's accounts-payable team can file against the original, and draws the credit down against the balance. If the customer already paid, the same note sends the money back as a linked refund, and paid stays paid.
curl -X POST https://api.withflintpay.com/v1/credit-notes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: credit-note-inv-0231-01" \
-d '{
"invoice_id": "inv_1kmn0aExample",
"reason": "returned_goods",
"memo": "Two bags arrived damaged.",
"credit_note_lines": [
{
"invoice_line_item_id": "invli_1kmn0aExample",
"correction": { "type": "quantity", "quantity": 2 }
}
]
}'Point at the invoice line and say how many. You never compute the money.
{
"data": {
"credit_note_id": "cn_1kmn0aExample",
"status": "draft",
"reason": "returned_goods",
"credit_note_lines": [
{
"credit_note_line_id": "cnli_1kmn0aExample",
"description": "Huehuetenango, 5 lb bags",
"quantity": 2,
"subtotal_money": { "amount": 12400, "currency": "USD" },
"tax_money": { "amount": 992, "currency": "USD" },
"total_money": { "amount": 13392, "currency": "USD" }
}
],
"total_money": { "amount": 13392, "currency": "USD" }
}
}Two of twenty bags is a tenth of the line, so the note carries a tenth of its tax. A named amount works too, when the correction is a rate and not a count.
# numbers it CN-1001 and renders the PDF
curl -X POST \
https://api.withflintpay.com/v1/credit-notes/cn_1kmn0aExample/issue \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: issue-cn-1kmn0a-01"
# apply it, and the balance falls
curl -X POST \
https://api.withflintpay.com/v1/credit-notes/cn_1kmn0aExample/allocations \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: allocate-cn-1kmn0a-01" \
-d '{ "amount_money": { "amount": 13392, "currency": "USD" } }'Issue assigns the next credit note number with your prefix and renders the PDF. Allocation is what moves the balance, and it is the one call here that insists on an idempotency key, because it is the one that changes what is owed.
{
"data": {
"credit_note_allocation": {
"credit_note_allocation_id": "cna_1kmn0aExample",
"amount_money": { "amount": 13392, "currency": "USD" },
"allocated_at": "2026-09-14T17:02:40Z"
},
"credit_note": {
"credit_note_id": "cn_1kmn0aExample",
"credit_note_number": "CN-1001",
"status": "issued",
"unallocated_money": { "amount": 0, "currency": "USD" }
},
"invoice": {
"invoice_id": "inv_1kmn0aExample",
"status": "partially_paid",
"credit_money": { "amount": 13392, "currency": "USD" },
"outstanding_money": { "amount": 40208, "currency": "USD" }
}
}
}The allocation, the note with what is left to apply, and the invoice with its new balance: $536.00 less $133.92 is $402.08. Reverse the allocation and the balance comes back, on an append-only record.
# already paid: issue the note and send the money back
curl -X POST \
https://api.withflintpay.com/v1/credit-notes/cn_1kmn0aExample/issue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: issue-refund-cn-1kmn0a-01" \
-d '{ "refund": { "reason": "requested_by_customer" } }'Add a refund to the issue call and the note's $133.92 goes back to the original payment method. Leave the amount out to refund all available credit, or name a smaller one. The refund carries the credit note id and the invoice id, and a paid invoice refunded in full still reads paid, with the refund status beside it.
Why the invoice is being corrected, printed on the note
- returned_goods
- order_adjustment
- billing_error
- goodwill
- other
Credit or refund
Credit reduces what is owed. A refund returns what was collected. If the invoice still has a balance, allocate the credit note against it. If it was already paid, refund the note, in the issue call or later against an issued note. A return with no billing correction behind it still goes through the standard refund call against the order.
- POST /v1/credit-notes
- POST /v1/credit-notes/{credit_note_id}/allocations
- POST /v1/credit-notes/{credit_note_id}/refunds
- refunded_money
- POST /v1/refunds
- refund_status
- POST /v1/invoices/{invoice_id}/void
- POST /v1/invoices/{invoice_id}/mark-uncollectible
The other three endings
Refund the order the invoice describes, item by item, with the same call every order uses. The invoice tracks the money returned on its own axis.
POST /v1/refundsVoid a bill that should never have existed. The order underneath is released to be edited or collected again.
POST /v1/invoices/{invoice_id}/voidWrite off a balance that will not be paid, in one call, and the invoice closes with the amount written off on it.
POST /v1/invoices/{invoice_id}/mark-uncollectible07The document
Everything accounts payable asks for, already on it.
Your prefix on the number, their PO number on the page, the service date, a remit-to address, fine print, and a PDF that never changes after issue. Copy their accounting inbox on every send. Their team sees every invoice in the account Flint hosts. Nothing here is a template you maintain.
"invoice_number": "INV-0231"Numbered, frozen, filed
Issue assigns the next number with your prefix, freezes the line items and totals after tax runs, and renders the PDF from that snapshot. Nothing that happens to the order afterward changes what the customer was billed.
- invoice_number_prefix
- snapshot
- GET /v1/invoices/{invoice_id}/pdf
"po_number": "PO-4417", "service_at": "2026-07-31T00:00:00Z"The fields their AP system wants
PO number, your reference, the service date, a remit-to address, a memo, and fine print, on the page, in the email, and on the PDF. Copy accounting on the first send and every reminder.
- po_number
- reference
- service_at
- remit_to_address
- cc_emails
- footer
GET /v1/me/invoicesIn the customer's own account
A customer signed in to the account Flint hosts sees every invoice you have sent them, pays the open ones, and downloads the PDF and any credit note, without hunting for the email.
- GET /v1/me/invoices
- GET /v1/me/invoices/{invoice_id}/pdf
- GET /v1/me/invoices/{invoice_id}/credit-notes
"merchant_id": "mer_2bqr7dExample"Your merchants' invoices too
If your product invoices for other businesses, each merchant you onboard issues under its own name, numbering, and account, from the same endpoints with a key scoped to it.
- merchant_id
curl -X POST https://api.withflintpay.com/v1/invoices \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: invoice-north-street-2026-07" \
-d '{
"quick_pay": {
"customer_id": "cus_1kmn0aExample",
"line_items": [
{
"name": "Huehuetenango, 5 lb bags",
"quantity": 20,
"unit_price_money": { "amount": 6200, "currency": "USD" }
},
{
"name": "Cold brew concentrate, 1 gal",
"quantity": 10,
"unit_price_money": { "amount": 4600, "currency": "USD" }
}
]
},
"collection": {
"mode": "buyer_initiated",
"payment_policy": {
"enabled_payment_options": [
"card",
"apple_pay",
"google_pay",
"ach_debit"
],
"show_cost_comparison": true
}
},
"payment_due": {
"type": "payment_terms",
"invoice_payment_term_id": "ipt_1kmn0aExample"
},
"recipient_email": "ap@northstreet.example",
"cc_emails": ["owner@northstreet.example"],
"po_number": "PO-4417",
"memo": "Thanks for another great month."
}'Line items or an order, how to collect, when it is due, who gets it, and what it says. Everything else has a default in your settings.
# numbers it, freezes the document, mints the link, emails it
curl -X POST \
https://api.withflintpay.com/v1/invoices/inv_1kmn0aExample/issue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: issue-invoice-north-street-2026-07" \
-d '{ "delivery_mode": "email" }'Numbered, frozen, linked, and emailed in one operation, and the delivery result comes back with it.
{
"data": {
"invoice": {
"invoice_id": "inv_1kmn0aExample",
"invoice_number": "INV-0231",
"status": "open",
"issued_at": "2026-08-03T15:31:00Z",
"due_at": "2026-09-02T00:00:00Z",
"outstanding_money": { "amount": 183600, "currency": "USD" }
},
"public_url": "https://checkout.withflintpay.com/i/ivat_1kmn0aExample#...",
"delivery_attempt": {
"invoice_delivery_attempt_id": "indel_1kmn0aExample",
"delivery_type": "send",
"to_email": "ap@northstreet.example",
"status": "sent",
"sent_at": "2026-08-03T15:31:02Z"
}
}
}The invoice is open and collectible when this returns, whatever the email did. A failed send is retried with one send-reminder call.
Every invoice and credit note event
- invoice.created
- invoice.issued
- invoice.issue_failed
- invoice.sent
- invoice.updated
- invoice.marked_uncollectible
- invoice.paid
- invoice.partially_paid
- invoice.payment_processing
- invoice.payment_failed
- invoice.payment_attempt_canceled
- invoice.payment_attempt_expired
- invoice.manual_payment_recorded
- invoice.manual_payment_reversed
- invoice.overdue
- invoice.reminder_due
- invoice.late_fee_due
- invoice.refunded
- invoice.partially_refunded
- invoice.credited
- invoice.delivery_succeeded
- invoice.delivery_failed
- invoice.voided
- invoice.collection_blocked
- invoice.collection_block_resolved
- credit_note.created
- credit_note.updated
- credit_note.issued
- credit_note.voided
- credit_note.allocation_created
- credit_note.allocation_reversed
Every payload identifies the invoice and carries its state after the event, so most handlers never fetch. Webhooks guide
08Proof
What you stop building.
One call creates the invoice, from line items or an order you already have.
POST /v1/invoicesIssue numbers it, freezes the document, mints the hosted link, and emails it, in one operation.
POST /v1/invoices/{invoice_id}/issueThe hosted page offers the options you froze on the invoice, and hides any whose cap the total exceeds.
payment_option_limitsThe page tells the buyer what paying by bank saves, from your rates.
show_cost_comparisonA term computes the due date and carries the late fee; a schedule splits the invoice into a deposit, installments, and a balance.
schedule_entriesReminders fire on your day offsets, in the invoice's timezone, and a payment cancels the rest.
days_from_dueA declined saved card retries on your schedule without another call.
retry_day_offsetsA check records against the same balance as a card, and a bounced one reverses back out.
POST /v1/invoices/{invoice_id}/manual-paymentsEvery send and reminder is a row with an outcome, and the first open stamps the invoice.
viewed_atA credit note credits lines with their tax share, then draws the balance down or refunds a paid invoice.
POST /v1/credit-notes/{credit_note_id}/allocationsThe aging report is one call.
sort_by=outstanding_moneyreviewed 2026-09-20 against the invoicing and credit notes guides · corrections: Flint Help
09Start
From a sandbox key to your first invoice in five minutes.
Free sandbox keys, no credit card. In a sandbox the recipient is you, so the invoice email and the reminder land in your own inbox.
Node
CLI
flint invoices create \
--order ord_1kmn0aExample \
--recipient-email you@example.com
flint invoices issue @last.inv --delivery-mode email
flint invoices send-reminder @last.inv
flint invoices get @last.invCreate it against an order, issue it, send yourself a reminder, then read it back.
Open the link in the email and pay with 4242 4242 4242 4242, any future expiry, any CVC. Then issue a second one, record a partial check against it with the manual-payments call, watch it turn partly paid, and reverse the check to watch the balance come back. That is the whole receivable, in one sitting.
Then read these
- 01InvoicingCreate, issue, collect, follow up, close.
- 02Credit notesCorrecting an issued invoice, with a linked refund when it was already paid.
- 03RefundsReturning money that was collected.
- 04Links vs sessions vs invoicesWhich surface fits the sale.
- 05
Skip the wait: npm install -g @flintpay/cli && flint signup creates your account and a sandbox key from the terminal. CLI guide
FAQ
Questions worth asking first.
What can a customer pay an invoice with?
Cards, Apple Pay, Google Pay, Affirm, and ACH debit, on a hosted page Flint emails for you. You choose the set per invoice with the payment policy, and it is frozen on the invoice at issue. A payment option limit hides an option once the invoice total passes the cap you set, so large invoices go to bank debit. With the cost comparison on, the page tells the buyer what paying by bank saves. ACH debit that is still processing shows the buyer the expected settlement date on the page.
Can Flint charge the card on file instead of emailing a page?
Yes. Create the invoice with automatic collection and a saved payment method, and issue freezes that method onto it. The collect endpoint charges it off-session, and a decline retries on the day offsets in your autopay retry policy without another call from you. Every attempt, including the declined ones, is a record you can list. Autopay runs on reusable saved cards; ACH debit and Affirm invoices collect through the hosted page.
Can one invoice take a deposit and installments?
Yes. Send schedule entries on the draft: a deposit due at issue or on a date, installments on dates, and a balance on the invoice due date, each as a fixed amount, a percentage, or the remainder, up to 14 entries. The hosted page asks for what is due now rather than the whole balance, currently_due_money tells you the same figure, and each entry carries its own paid, credited, and outstanding amounts. Leave the array out and the invoice is due in one payment on its terms.
Can Flint charge a late fee?
The payment term carries the policy, fixed or a percentage, with a grace period. Once that period passes with a balance remaining, Flint computes the fee from what is still owed and tells you with an event. Charging it is your call: one request assesses the fee onto the invoice, which raises the amount due and prints a dated addendum on the hosted page and the PDF, while the issued lines, tax, and original total stay fixed. Waive the unpaid remainder with a reason only you can see, and the fee's own paid, waived, and outstanding amounts stay on the invoice.
What happens when a check bounces?
Reverse it. The reverse endpoint takes the amount and the check's reference and puts the balance back, on a paid invoice as well as an open one, so a check that closed an invoice and then returned unpaid reopens it correctly. Status follows the money in both directions. A reversal only undoes recorded offline amounts, never card money, and it cannot exceed what was recorded, so a card payment is never quietly undone.
Do reminders send on a schedule?
On the schedule you write, as day offsets from the due date, negative ones before it. Flint sends each reminder for you with the live payment link, in the invoice's timezone, and freezes the list onto the invoice at issue so a later settings edit never rewrites a receivable already out. When the customer replies, pause the cadence on that invoice with one call and resume it later; a one-off send-reminder still works while it is paused. Every reminder is also a webhook event, so a caller-managed invoice can send from your own system on the same cadence.
How do I know whether they ever opened it?
The first time the customer opens the hosted page stamps viewed_at on the invoice. Every send and every reminder is a delivery attempt with a status and, when it fails, the reason, and invoice.delivery_failed fires on a bounce. The invoice's own event log holds the rest: issued, viewed, each payment, each reminder, each reversal, with the actor and the time. When a customer says they never got it, the conversation ends there.
What is the difference between a credit note and a refund?
A credit note reduces what is owed. A refund returns what was collected. Credit the lines that were wrong and Flint computes their share of discount and tax, numbers the credit note with your prefix, renders a PDF the customer's accounts-payable team can file against the original, and draws the credit down against the balance when you allocate it. If the invoice was already paid, refund the credit note instead: the money goes back to the original payment method, and the refund stays linked to the note and the invoice. The invoice tracks refunds separately from its status, so a paid invoice stays paid.
Can a customer find an invoice without the email?
Yes. A customer signed in to the account Flint hosts sees every invoice you have sent them, pays the open ones, and downloads the PDF and any credit notes. If an emailed link was forwarded somewhere it should not have been, regenerate it: the old link and any checkout credentials taken from it stop working immediately, a payment already in flight survives, and every reminder after that carries the new link.