SaaS
Subscription Billing Migration
Built by Reymart Dalisay
Moved a B2B SaaS company off hand-rolled billing onto a metered subscription model without reissuing a year of invoices.
Builder email verified
Verification
- Type
- Professional
- Category
- SaaS
- Published
- Jul 25, 2026
- Updated
- Jul 25, 2026
About this project
- The problem
The company had been invoicing manually from spreadsheets since it was five people, and by the time I came in it was a finance person's full week every month plus a long tail of corrections. Sales had also started selling usage-based tiers the system couldn't represent, so those contracts were being tracked in a shared document and billed by hand. The goal was automated metered billing that matched what sales had actually signed, without changing anyone's existing invoice terms mid-contract.
- My role
I was brought in as a contractor for what was scoped as three months and ran about five. I worked alone on the billing side, reporting to the head of engineering, with the finance manager as the person who decided what correct meant. Toward the end I also wrote the internal documentation and ran two handover sessions, since I was leaving and nobody else had been in the code.
- What I owned
I built the metering pipeline that aggregates raw usage events into billable quantities, the subscription model that maps a signed contract to those quantities, and the Stripe integration that turns the result into an invoice. I owned the migration of about four hundred existing customers, including the reconciliation script that compared what the new system would have billed against what was actually billed for the previous three months. I also wrote the dunning workflow for failed payments. I didn't touch the product's own usage instrumentation — I consumed what was already emitted and worked around its gaps.
- Technical & product decisions
The decision I'd defend hardest is that I refused to backfill or restate historical invoices. Finance wanted the new system to be the record for everything; I argued that recomputing a year of invoices with new logic would create differences we'd have to explain to customers one at a time. We froze history in place and ran the new system forward from a cutover date. I also chose to compute billable quantities in a nightly batch rather than continuously, because a subscription invoice is a monthly artifact and streaming aggregation would have added operational surface for no business benefit. AWS Step Functions handled the monthly run because I wanted the retry and audit behaviour without owning a scheduler.
- Constraints
Usage instrumentation was incomplete — two of the metered features didn't emit events at all when I started, and I had to get another team to add them, which set the timeline back about a month. Every customer's contract had to bill identically before and after cutover or finance wouldn't sign off, so the reconciliation had to reach exact agreement, not close agreement. There was also no staging environment with realistic data, so I built a fixture generator first, which felt like a detour and saved the project.
- Result & impact
The monthly close went from about a week of one person's time to roughly half a day of reviewing exceptions. Usage-based contracts stopped being tracked in a shared document — sales can now sell a tier the system understands, which they did nine times in the first quarter. The reconciliation run caught eleven customers who had been under-billed for months, worth more than my contract, and two who had been over-billed, which finance refunded. About four months after I left they added a new metered dimension themselves without contacting me, which I take as the real result.
- Who else worked on it
The finance manager reviewed every reconciliation run and was the reason the migration was trustworthy; she found discrepancies I'd have shipped past. An engineer on the product team added the missing usage events and later took ownership of the whole thing. I also leaned on their head of engineering to say no to a mid-project request to add proration rules, which would have doubled the scope.