The Problem
Managing a small fleet of rental vehicles in Sydney with Google Sheets, WhatsApp messages, and manual bank statement reconciliation gets messy fast. Every week, each renter owes a fixed amount. The job: track who owes what, send reminders, collect payments, reconcile records.
The breaking point: reconciling payments late one night and realising we'd double-counted one renter while missing another entirely. Payments weren't just late, they were invisible. Bank transfers showed as random amounts from random names. Matching them was a recurring weekly exercise that still produced errors.
The business cost:
What We Built
We built RentalsCube, a product we now use to run our own fleet and offer to other operators with the same problem. The stack is a React front end built with Vite, an Express API using tRPC, MySQL for the database and Stripe Connect for payments. RentalsCube launched in November 2025.
Why React, Express and tRPC? Speed to market. tRPC gives the front end typed calls into the API, so a change on the server breaks the build instead of breaking a screen in production. For a SaaS where shipping quickly matters more than architectural perfection, pick the tools you're most productive in.
Why MySQL over NoSQL? Fleet management data is relational. Vehicles have many rentals. Rentals belong to one customer. Payments belong to one rental. MySQL handles these relationships with foreign keys, joins and constraints that prevent the data inconsistency that plagued the spreadsheet.
Why Stripe Payment Links over full embedded checkout? The point was to eliminate bank transfer chaos. Full checkout with saved cards and recurring billing would have taken much longer to build. Payment Links got most of the outcome for a fraction of the effort: generate a unique link per renter per week, email it on the due day, and record the payment automatically via webhook. Stripe Connect handles the payments side.
Why automated email? Every week on the renter's due day, the system sends an email with their payment link. Unpaid after 48 hours? Automatic reminder. Days overdue? Escalation email to the fleet owner. This replaced the manual WhatsApp chasing.
The Build
Core CRUD. Vehicle management: add, edit, remove vehicles with make, model, registration plate, status. Customer management: renter profiles with contact details. Rental creation: assign vehicle to customer with weekly amount and payment schedule.
No styling at first, just forms that worked. We used it from day one by entering our own fleet data.
Payments. Stripe integration, webhook handling and the automated email pipeline. This was the hardest part.
The critical challenge: Stripe webhooks behave differently in development vs. production. We spent real time debugging a webhook that worked in test but failed in production because of a Stripe API version mismatch.
Key architecture decision: handle payment_intent.succeeded idempotently. Stripe retries failed webhook deliveries, so the same payment event might arrive more than once. Without idempotent handling, that's duplicate payment records.
We also built the owner dashboard: fleet size, active rentals, this week's payments, this month's revenue, outstanding balance and overdue alerts. It's the screen fleet owners actually live on.
Polish and launch. A customer portal for renters to view their rental details and payment history. Overdue reminder emails. Receipt generation. Mobile responsiveness: most renters check email on a phone, so payment emails and Stripe checkout had to work well there.
Migrating Off the Spreadsheet
We migrated our own fleet off Google Sheets onto RentalsCube. Entered all vehicles, customers, and active rentals. Set up weekly payment schedules. Automated emails started going out and payments began coming in via Stripe link, without a WhatsApp message, bank transfer or manual reconciliation.
The weekly payment-chasing ritual was over.
What We'd Build Differently
Recurring Stripe subscriptions from day one. Payment links require renters to click every week. Subscriptions with saved cards would automate even further. We left this out of v1 to ship faster, and it's the obvious next step.
SMS alongside email. Some renters don't check email reliably. SMS payment reminders would catch more late payments.
Multi-currency support. Not needed while we operate in Australia, but it would matter if we sold to operators elsewhere.
None of these gaps were worth delaying launch. We found every one by using the product ourselves, which is the point of shipping fast and building for yourself first.
Running a rental fleet or another operation that's outgrown its spreadsheet? Book a call and we'll talk through what a fixed-scope build would look like.