03 · Technology

A matching engine that understands roads, time and trust.

Pairing commuters is a geospatial and scheduling problem. Our prototype solves it with PostGIS, self-hosted OSRM road routing and a transparent scoring model, running asynchronously so the app stays instant at rush hour.

8 km
endpoint search radius
4 km
route corridor buffer
≤ 100
candidates per job
0.28
minimum match score
Route-aware matching

We match trips, not dots on a map.

Point-to-point matching misses most real carpools. By storing each pilot's full road path as a PostGIS LineString, we can pair riders whose pickup and drop lie along that path, even when the two start points are kilometres apart.

Pilot starts · KoramangalaPilot officePassenger pickupPassenger drop4 km corridor8 km search radiusPilot road path (OSRM)Passenger tripMatch corridor buffer
Full match

Pickup and drop both within 2.5 km of the pilot's start and end.

e.g. Neighbours working in the same tech park.

Partial match

Pickup and drop sit close to the pilot's road path with ≥ 75% overlap.

e.g. Rider joins 3 km down the pilot's highway and gets off before the pilot's office.

Corridor match

Both ends fall inside the 4 km corridor around either route line.

e.g. Rider is a short detour off the pilot's usual route.

Pipeline

Six stages from “request” to “ranked match card.”

1

Route captured

Origin, destination, window and days, plus the OSRM road polyline and distance.

2

Job enqueued

The API returns instantly. A BullMQ job carries the match work off the request path.

3

Spatial pre-filter

PostGIS ST_DWithin on GIST indexes: 8 km endpoints or a 4 km corridor, capped at 100.

4

Schedule filter

Shared weekdays (or the ride date) and overlapping departure windows.

5

Score & rank

Weighted route, time, detour and trust score. Anything below the threshold is dropped.

6

Notify both sides

Deduped pending matches with a 24 h TTL. Notifications go through their own queue.

Every active pilot offer in the citycommute_routes · is_driver = truePostGIS pre-filterST_DWithin 8 km · 4 km corridor · GIST · ≤ 100Schedule compatibleshared weekdays · overlapping windowsScored ≥ 0.28route · time · detour · trustRanked match cardsdeduped · 24 h TTL · notified
Each stage narrows the candidate set cheaply before the more expensive scoring runs.
Scoring model

Transparent, tunable, and explainable to users.

Every match gets a composite score from four signals. Because the weights are explicit, we can show riders why a pilot ranks first, and tune the model from real acceptance data once we launch.

35%
Route overlap
How much of the passenger's trip lies on the driver's real road path (OSRM polyline).
35%
Time overlap
Minutes of intersection between both departure windows.
20%
Low detour
Inverted pickup detour in km — shorter is better.
10%
Driver trust
Rolling trust score from ratings and verified documents.
score = route  × 0.35
      + time   × 0.35
      + (1 − min(detourKm / 10, 1)) × 0.20
      + (trust / 5) × 0.10
Worked example
Priya → Arjun, 8:30 AM window
Route overlap · 35%Time overlap · 35%Low detour · 20%Driver trust · 10%
SignalExample inputValueContribution
Route overlap82% of trip on pilot's path0.82+0.287
Time overlap45 of 60 min window overlap0.75+0.262
Low detour1.2 km pickup detour0.88+0.176
Driver trustTrust score 4.7 / 50.94+0.094
Match scorethreshold 0.280.82
End to end

From seat offer to settled payment.

Every interaction between the apps, API, queue, workers and database, in the order it happens for a single shared ride.

Pilot appPassenger appAPIRedis queueMatch workerPostgres + PostGISPostPOST /routes · seat offerstore route + OSRM polylinePOST /routes · ride requestenqueue match job201 · searchingMatchprocess jobST_DWithin candidatesscore → insert matchesGET /matches · poll 2.5 sRideaccept matchcreate ride · fare in paiseen-route → start → completePaypay via UPI (Razorpay)payment settled · 3% split
Engineered for rush hour

Commute demand spikes at 9 AM. Our system is built for that curve.

GIST spatial indexes

Candidate lookup is an index scan, not a full table scan, so latency stays flat as the city grows.

Hard candidate cap

Each job scores at most 100 candidates, which bounds CPU per match whatever the density.

Async by default

Matching can take 100 ms – 2 s at peak. Moving it off the HTTP thread keeps OTP, profile and payment p99s low.

Reverse matching

A new pilot offer enqueues jobs for nearby waiting riders. Supply finds demand, not only the other way round.

Retries with backoff

Three attempts with exponential backoff absorb transient DB or Redis failures without losing a request.

Dedupe + TTL

The same pilot–rider pair is never matched twice. Stale matches expire after 24 h.

Data moat
Every request will make matching smarter

Unfulfilled requests are kept, not deleted. After launch, that becomes a live heatmap of where pilot supply is missing, by corridor and by hour.

Over time, recurring pairs, ratings and trust scores form a commute graph that new entrants can't copy.