Dan Petrescu
Taxi platform

Taxi platform

Validating a fare algorithm against Romanian regulation, and designing call masking on Amazon Connect for a taxi platform with over 1M users.

See the project summary

1M+

users on the platform

≤0.45 lei

fare deviation across reference rides

4

reference rides driven and measured

344h

billing system estimate, split into two releases

Context

The platform runs a taxi fleet serving more than a million users. The previous version worked, in the sense that cars moved and money arrived, but two things were breaking down as the fleet grew. Fares computed on the phone did not match what a passenger expected, and dispatch depended on people answering phones. Both problems are the kind that get worse exactly when business gets better.

The fare problem is not a software problem first. In Romania a taxi fare is regulated: the tariff structure is fixed, and the meter has to produce a number a regulator would accept. A phone measuring distance from GPS is a much noisier instrument than a wheel sensor. Tunnels, urban canyons and stop-and-go traffic all push the number around. The question was not 'can we compute a fare' but 'can we compute a fare that survives inspection'.

Constraint

The tolerance was the constraint. We had a deviation band to stay inside, and no way to prove we were inside it except by measuring against something real. On top of that, the fleet wanted driver and passenger phone numbers hidden from each other — a standard expectation now, and one that touches telephony, privacy law and where the call recordings live.

Finally there was a budget. The billing and subscription work came out at a 344-hour estimate. That estimate was honest and it was too large to sit between the fleet and a working v3.

Decision

For the fare engine we rejected the simulation route. It was tempting: generate GPS traces, replay them, tune the filter until the error goes to zero. It produces a very good-looking chart and proves nothing, because the errors you care about are the ones your simulator does not know how to make. We drove four reference rides on real routes, measured them properly, and tuned against those. The result held to a 0.45 lei deviation. It took longer and it is the only version of the work a regulator will actually read.

For call masking we rejected running our own SIP stack. Owning the telephony layer gives full control over routing, recording and cost per minute, and it also means owning an on-call rotation for a real-time system nobody on the team had operated before. We put masking on Amazon Connect in the Frankfurt region instead. Call data stays in the EU, the proxy-number logic was live in days, and we accepted the vendor lock-in knowingly rather than discovering it later.

For billing we rejected shipping the whole 344 hours as one release. Invoicing with SmartBill went first, because that is the part that turns rides into revenue. Subscriptions and the suspension logic for unpaid accounts followed as a second release. Same total effort, months earlier on the part that pays for it.

What shipped

A GPS taximeter fare algorithm validated across four reference rides, staying within 0.45 lei. Call masking and proxy numbers on Amazon Connect in Frankfurt. A billing layer with SmartBill invoicing, subscription handling and automated suspension for unpaid accounts, delivered in two releases. On top of that, AI dispatch agents that assign rides without an operator in the loop for the routine cases.

Numbers

Fare deviation inside the regulatory tolerance at ≤0.45 lei across the reference set. Four reference rides used as the validation baseline. 344 hours estimated for the billing system, delivered as two releases rather than one. The platform serves more than a million users.

What I'd do differently

I would drive the reference rides in week one instead of week three. We built a lot of filtering logic before we had ground truth to tune it against, and some of that work was thrown away once the real traces arrived. Ground truth is cheap to collect and expensive to defer.

I would also have written the two-release billing split into the original estimate rather than arriving at it later. Presenting a 344-hour number and then restructuring it reads as a walk-back, even when it is the right call.

Want this for your product?

Fixed-price scope in the first call. No discovery phase invoice.