Money & Operations (Admin)
Phase 2 — pricing, promos, commission, cancellations, payouts, reports. All money moves through an immutable double-entry ledger, so every figure reconciles.
Pricing
Fares are metered per vehicle type: base + per-km + per-minute, floored
at a minimum fare. On top of that:
| Modifier | Where configured | How it works |
|---|---|---|
| Surge / night | pricing_rules table |
Time-window multipliers (bps); multiple matching rules compound. A night rule (22:00–06:00, 1.25×) is seeded by default. |
| Waiting charge | per-minute rate | Charged for driver wait time. |
| Toll | per-ride flat | Added to the fare. |
All amounts are minor units (cents/paise) — integer math, never floats.
Commission
Each completed ride splits the fare automatically:
driver earning = fare − commission, platform = commission. The rate is
commission_bps on the vehicle type (e.g. 2000 = 20%), else the
installation default. Commission is floored so the driver keeps the
sub-unit.
Promos & referrals
- Promo codes (
promo_codes): flat or percent (with a cap), min-fare, per-user + global usage limits, validity window. Two examples seeded (WELCOME20,FLAT50). - Referrals (
referrals): refer-a-rider and refer-a-driver are separate, each with its own reward amounts. Rewards are wallet credits funded from apromo_liabilityaccount (visible in reporting).
Cancellations
Admin-configurable per vehicle type (cancellation_policies):
- Free-cancel window (seconds after a driver accepts).
- Late-cancel fee (after the window).
- No-show fee (driver arrived, rider absent).
- Driver/admin cancels → no rider charge.
Fees are charged to the rider wallet (which may go negative = debt, settled on next top-up/ride), credited to platform revenue.
Payouts
Drivers withdraw wallet earnings to their bank. Flow:
request → process → paid | failed. On request the funds are reserved
(held); on success they leave the platform; on failure they return to the
wallet. Payout rails are pluggable (manual/cash today; RazorpayX/Stripe
Connect drop in). Processing requires the payout.approve permission.
Reports
GET /api/reports/{revenue|drivers|customers|trips|tax} (permission
report.view), each with optional ?from=&to= date range:
- revenue — commission + cancellation fees collected.
- drivers / customers — earnings / spend + trip counts.
- trips — counts by status, total distance + fare.
- tax — taxable base (Phase 4 applies the per-country rate).
Analytics (admin → Insights → Analytics)
Five deeper reports behind the same report.view permission, all real SQL
over rides + the ledger, all ?from=&to= bounded, all bucketing in the
market timezone and returning money as integer minor units:
| Endpoint | What it answers | Parcels? |
|---|---|---|
GET /api/reports/funnel |
requested → accepted → started → completed conversion + per-stage drop-off. Stage membership is by lifecycle timestamp (an accepted-then-cancelled ride still reached "accepted"). | No — passenger only. |
GET /api/reports/service-mix?bucket=day|week|month |
city / rental / intercity / parcel share of bookings + completed revenue per bucket. | Yes — as its own segment. |
GET /api/reports/cohorts?interval=month|week |
rider retention triangle: cohort = period of first completed trip; cells = share active again N periods later. The range bounds cohorts, never activity. | No — a parcel sender is not a retained rider. |
GET /api/reports/driver-retention?churnDays=7..365 |
active/new/returning drivers per month, month-over-month churn, plus an N-day "gone quiet" headline. N: query param → market config analytics.driverChurnDays → 30. |
Yes — completed work of either kind counts; a parcel-only driver is not churned. |
GET /api/reports/zones |
per-zone (pickup point, one zone per ride: highest priority, most specific) trips, parcels, gross fares, ledger commission, cancel rate, avg request→start wait. Rides outside every zone report as an explicit "outside" row. | Counts split by kind; money pools both — zone revenue is zone revenue. |
Zone commission comes from platform_commission ledger credits per ride, so
the zone table reconciles with the revenue report to the paisa.