A customer clicks Pay. The request times out. Your server has no payment ID to store. The provider may still have taken the money.
Should the system try again, restore access, wait for a webhook or ask someone to investigate? A line in a quote that says ‘payments: 2 days’ does not answer that question. It might cover a perfectly reasonable managed checkout integration. It might also hide decisions nobody has scoped.
The useful question is who owns each part of billing. I built an application-owned billing layer for KRI, a booking SaaS running on Mollie. Its implementation is one example of that ownership, not the minimum architecture every SaaS needs.
Choose the Billing Model Before Estimating the Work
There are several ways to divide responsibility:
| Model | What it can take on | What the application still needs to handle |
|---|---|---|
| Payments API | Payment methods, authorisation, collection and payment status | Subscription rules, documents, tax decisions and account access, unless handled elsewhere |
| Managed billing | Subscription schedules, supported pricing models, invoices and collection workflows; tax tooling may be an additional product | Configuration, integration, state synchronisation and the product’s access policy |
| Merchant of record | Acts as the seller for covered transactions and handles the corresponding tax and billing obligations under its agreement | Product delivery, integration, supported-market checks and obligations outside that agreement |
These are models, not interchangeable promises. Check the actual provider, product and contract.
Stripe Billing supports recurring and usage-based pricing; Stripe Tax provides tax calculation functionality. Different customer tax treatments or a variable price do not automatically require custom billing. Stripe Billing features.
Mollie also has a Subscriptions API, including an endpoint to update the amount of future payments. ‘Our amount changes’ is therefore not enough, by itself, to rule it out. KRI calculates its own billing periods, amounts and documents and charges a mandate directly. That choice leaves more state in the application; another product should evaluate the managed option against its own requirements. Mollie update subscription.
Issuing a Document Creates Work Beyond Taking Payment
KRI stores issued invoices as snapshots: buyer details, line items, VAT treatment, currency and exchange-rate information do not change when the customer later edits their profile. Corrections preserve the original document and an auditable relationship to the correcting document.
Its full-cancellation workflow issues a credit note. That does not mean every invoice error everywhere requires cancelling the entire invoice. The appropriate correcting or replacement document depends on the error and applicable rules.
KRI uses separate invoice and credit-note sequences per customer, with transactional allocation that avoids consuming a number on a rolled-back issue. This is an implementation choice. Finnish Tax Administration guidance requires unique sequential identification and permits multiple series; it also describes references for correcting invoices. The requirement should not be confused with KRI’s particular counter design. Vero: VAT invoice requirements.
For a quote, ask who issues the documents and how corrections reach the accountant. A provider may already supply the required documents. Rebuilding that capability only helps if the existing one does not meet the business’s needs.
Tax Needs Inputs, an Outage Policy and a Defined Market
Customer location, business status, the service being sold and the seller’s registration affect VAT treatment. ‘EU customer’ alone is not enough information. For cross-border EU B2B services under the general rule, reverse charge commonly applies; domestic sales and B2C electronic services follow different rules. Define the actual sales scope before encoding a tax decision. European Commission: place of taxation for services.
KRI validates EU VAT numbers through vatnode, keeping valid, invalid and unavailable responses separate. Its current outage policy retries and then charges VAT if validation remains unavailable. That is the product’s fallback policy, not evidence that an unavailable register legally changes a customer’s status. It needs review for the intended market and a process for correcting the treatment when supporting information becomes available.
A different system might pause invoice issuance or route the case for review. The estimate should include whichever behaviour the business chooses, along with stored evidence and the correction path. It should not silently turn a network exception into a tax rule.
Foreign Currency Needs a Documented Accounting Policy
KRI freezes an ECB reference rate and its date when issuing a non-euro invoice. A credit note reversing that invoice copies the original rate so the document pair reverses consistently. If its required rate is unavailable, issuance stops instead of inventing a conversion.
This describes KRI’s implementation. The applicable conversion rules and the accounting treatment of settlement differences still need to be established for the business. A reversal of the original invoice does not erase real exchange-rate gains or losses on money later received or refunded.
In Finland, Vero specifically requires the VAT payable in euros on an invoice for domestic taxable sales made in another currency. That is more precise than claiming every foreign-currency invoice universally needs the same euro field. A managed provider may cover the required document and conversion workflow; assess that before building one. Vero invoice guidance.
Failed Payments Need a Product Decision
A declined card, a missing mandate and a payment awaiting confirmation are different states. Someone must decide how each affects access, reminders and the next collection attempt.
KRI has grace-period rules and keeps the billing page reachable so an owner can resolve the problem. Those are product choices. A SaaS could reasonably use a different grace period, allow invoiced credit, or delegate collection retries to its billing provider. What matters is that the behaviour is explicit and repeat failures do not accidentally extend access forever.
Cancellation and debt should also be distinguished. KRI’s current flow can refuse cancellation while an invoice remains outstanding. Other products stop future renewals while continuing to collect an existing balance. The business must choose an appropriate policy; a concurrency lock cannot decide it.
An Unknown Payment Outcome Is Not a Failed Payment
Return to the timed-out request. Sending a fresh charge because no response arrived risks taking payment twice. Provider idempotency helps, but its retention window matters: Mollie documents a one-hour response cache for matching idempotency keys. Mollie API idempotency.
KRI records an attempt before contacting the provider and uses a partial unique index to allow only one attempt in its protected live states per invoice. Another constraint limits live invoices for the same customer and period. An unresolved attempt blocks blind recharging while reconciliation seeks evidence; cases it cannot resolve go to human review.
The index alone cannot make a database transaction and a remote payment atomic. The protection comes from the whole state machine: durable intent, provider idempotency, reconciliation and a rule that uncertainty is not permission to try again. A managed billing system may own much of that machinery; the application still needs to understand how to recover its local state.
Concurrent Decisions and Duplicate Notifications Are Different Problems
KRI uses a shared per-tenant lock around issuing, charging, crediting, cancelling and detaching a card. Participating operations read the current state after acquiring it. The allowed cancellation-versus-renewal result follows KRI’s policy, rather than two workers independently acting on stale facts. Testing that ordering requires more than two concurrent promises.
Notifications need their own handling. KRI treats Mollie notifications as a reason to fetch authoritative payment information, then applies conditional local transitions. A duplicate notification should not duplicate a financial effect. Chargebacks require checking the relevant reversal information too; a payment’s original ‘paid’ status alone is not a complete view of later money movements.
A webhook handler, a billing lock and provider idempotency cover different failure modes. Listing all three in a proposal is less useful than explaining which state each protects and who investigates when they disagree.
What a Short Estimate Can Honestly Include
A hosted checkout backed by managed subscriptions may be a small integration even when prices or tax treatments vary, provided the provider supports the required model. The work still includes configuration, account mapping, webhook handling, access synchronisation and testing the relevant failures.
My SaaS build checklist gives three to four days for a defined Stripe integration. That is a scoped example, not a universal estimate or a promise that any billing requirement fits it. Custom documents, migration, unusual collection rules or reconciliation across systems can change the scope substantially.
Before signing, ask:
- Which system owns the subscription schedule, amount and payment state?
- Who issues invoices and corrections, and has the accountant accepted the flow?
- What happens when tax validation or a payment request times out?
- How do failed payments, cancellation and existing debt affect access and future renewal?
- Which failures recover automatically, and where does an unresolved case appear for a human?
A useful proposal answers these against your requirements and names any decisions still open. The number of days becomes meaningful once the responsibility is clear.








