/ Docs / Nearest-Partner Matching v1 · 2026
Geo · Matching

Nearest-Partner Matching

How a paid booking is turned into the right partner on the right vehicle at the lowest cost that still meets the speed tier — eligibility, the bundling-first cascade, scoring, dispatch, fairness, and relay legs.

1. Overview — what matching decides

Matching is the engine that takes a paid booking and answers one question: which partner, on which vehicle, should carry this parcel — and by which strategy? The inputs are everything the booking already knows about the job, and the objective is deliberately cost-minimizing: among all assignments that satisfy the speed tier and the vehicle constraints, pick the cheapest to serve. Cheap-to-serve is how RideChain undercuts Porter and Bluedart on a 15 km interior route while still paying partners fairly.

📦

Package shape

Size bucket (S/M/L/XL), weight bucket, category (documents, fertilizer, furniture, perishable…) and flags (fragile, perishable, cold, oversized). These set the eligible vehicle classes.

📍

Geo & time

Pickup/drop coordinates, distance, and the delivery time window. Geolocation answers "who is near?"; the window decides whether a slow bundle is acceptable.

Speed tier & price

Urgent / Express / Bundled milk-run, and the fare the booker paid. The tier is the hard constraint; cost is what matching minimizes under it.

🛡️

Trust tier

The partner's graduated trust level gates what they may be offered at all — new partners are limited to low-value, short, prepaid jobs (see Onboarding & KYC).

Matching does not work alone. It leans on Geolocation for nearest-partner queries (PostGIS + Redis GEOSEARCH), on Commission & Pricing for the rate card that makes one assignment cheaper than another, on trust tiers for eligibility, and on Fastest-Route Finding once a partner is chosen.

Mental model: matching is a filter-then-score pipeline. First throw away every partner/vehicle that cannot legally or physically do the job (eligibility); then among the survivors, rank by a cost-aware score and offer to the best. The cheapest legal assignment wins — not simply the closest.
flowchart LR
  B["Paid booking
(size, weight, category,
geo, window, tier, price)"] --> F["Eligibility filter
vehicle class × trust tier"] F --> S["Cost-aware scoring
& ranking"] S --> O["Offer to best partner"] O --> A["Assigned + ETA"] G["📍 Geolocation
nearest queries"] -.-> F P["📊 Pricing / rate card"] -.-> S T["🛡️ Trust tiers"] -.-> F classDef src fill:#e8f0fb,stroke:#1f5fae,color:#143d6e; class G,P,T src;
Matching at a glance: a paid booking is filtered to eligible partner/vehicle combinations, scored with a cost-aware function, and offered to the best candidate. Geolocation, pricing and trust feed the filter and the score.

2. Vehicle eligibility matrix

Before any scoring, matching narrows the partner pool to vehicles that can physically and legally carry the parcel. RideChain supports the full ladder of vehicles — cycle, bike, e-rickshaw, auto, Bolero, Tata Ace, tractor-trolley, mini-truck, tempo — and the eligible set is a function of (size bucket × weight bucket × category × distance). The booker may have overridden the recommendation at booking time; matching honours the chosen vehicle class as the floor.

Size bucketWeight bucketCategoryDistanceEligible vehicle classes
S< 2 kgDocuments / small parcel≤ 6 kmCycle · Bike
S< 2 kgDocuments / small parcel6–25 kmBike · E-rickshaw
M2–20 kgGeneral goods≤ 12 kmBike · E-rickshaw · Auto
M20–60 kgFertilizer / sacks≤ 15 kmAuto · Bolero · Tata Ace
L60–150 kgFurniture / bulkyanyTata Ace · Mini-truck · Tempo
L60–500 kgFarm / agri-bulkruralTractor-trolley · Mini-truck
XL> 150 kgHeavy / long-haulanyMini-truck · Tempo · Tractor-trolley
anyanyPerishable / cold-chainanyFastest eligible + cold flag required
anyanyFragileanyEligible set minus cycle (no padding); fragile handling
Worked examples. 2 documents, 6 km → cycle or bike (cheapest legs win the score). 50 kg fertilizer, 12 km → auto / Bolero / Tata Ace. Furniture → Tata Ace / mini-truck. Perishable → fastest eligible vehicle with the cold flag set so a slow bundle is never chosen for it.

Eligibility is also a trust gate and a document gate: motorized classes require a partner whose RC (VAHAN) and DL (Sarathi) are validated in Onboarding & KYC, and the per-class payout floor comes from the Commission & Pricing rate card. A vehicle the partner is not verified to operate is removed from the eligible set before scoring even begins.

flowchart TB
  J["Booking: size, weight,
category, distance, flags"] --> CAP{"Capacity fit?
weight & volume"} CAP -- "no" --> UP["Escalate to larger class"] CAP -- "yes" --> CAT{"Category constraints?"} CAT -- "perishable / cold" --> COLD["Require cold flag
+ fast vehicle only"] CAT -- "fragile" --> FR["Drop cycle, mark handling"] CAT -- "general" --> OK["Base eligible set"] UP --> DOC COLD --> DOC FR --> DOC OK --> DOC{"Partner verified
for this class? (VAHAN/Sarathi)"} DOC -- "no" --> RM["Remove partner"] DOC -- "yes" --> ELIG["Eligible partner × vehicle"]
The eligibility filter: capacity fit, then category constraints (cold-chain, fragile), then the document/trust gate. Only partners that survive all three reach the scoring stage.

3. The matching strategy — a cost-minimizing cascade

The single most important design choice is the order in which matching tries strategies. It is a cascade from cheapest-to-serve to most-expensive, falling through only when the cheaper option cannot meet the booking's constraints. This is what makes the bundled milk-run the default and on-demand the exception.

  1. Bundling-first (cheapest). Try to attach the parcel to an existing or planned route, or to a scheduled Block-Hub → village milk-run. Slightly slower, dramatically cheaper because partner time is shared across many parcels.
  2. On-demand (if urgent / no bundle). If the tier is urgent or no compatible bundle exists, dispatch the nearest eligible online partner directly — dedicated, faster, pricier.
  3. Reverse-auction / bid (heavy or long-haul). For large or long-distance jobs where a fixed rate is risky, broadcast to eligible heavy-vehicle partners and let them bid; the lowest acceptable bid wins.
  4. PUDO routing (via Points + hub). If no door-capable partner is sensible, route through RideChain Points and the Block Hub so the parcel rides shared infrastructure end to end.
flowchart TB
  START["Paid booking
eligible set ready"] --> URG{"Urgent tier?"} URG -- "no" --> BND{"Compatible bundle
or milk-run found?"} BND -- "yes" --> B1["① BUNDLING-FIRST
attach to milk-run
(cheapest, slower)"] BND -- "no" --> HVY URG -- "yes" --> HVY{"Heavy / long-haul?"} HVY -- "no" --> B2["② ON-DEMAND
nearest eligible online partner"] HVY -- "yes" --> B3["③ REVERSE-AUCTION
partners bid, lowest wins"] B2 -. "no door partner sensible" .-> B4 B1 --> DONE B2 --> DONE B3 --> DONE B4["④ PUDO ROUTING
via Points + Block Hub"] --> DONE["Assignment chosen"] classDef cheap fill:#e6f5ea,stroke:#2e8b57,color:#1d5a38; class B1 cheap;
The cost-minimizing cascade. Bundling is tried first and only abandoned when urgency or a missing bundle forces a pricier tier; reverse-auction covers heavy/long-haul; PUDO is the shared-infrastructure fallback. Each fall-through trades cost up for speed or feasibility.
The cascade decides the strategy; the actual vehicle path within a chosen bundle or auction win is solved as a routing problem — see the VRP in Fastest-Route Finding. Bundling economics roll up into Scale & Low-Cost.

4. The scoring function

Within whichever cascade branch is active, candidate partner/vehicle pairs are ranked by a single weighted score. Conceptually:

score = w₁·proximity(distance, ETA) + w₂·rating + w₃·acceptance_rate + w₄·vehicle_fit + w₅·trust_tier + w₆·fairness_rotation + w₇·green_bonus

TermWhat it measuresWhy it lowers cost / risk
proximity (distance / ETA)How close the partner is to pickup, by road ETA not crow-flies.Less dead-mileage to reach pickup → cheaper, faster, less fuel.
ratingRolling customer rating of the partner.Fewer failed handovers, disputes and re-deliveries.
acceptance_rateHow often the partner accepts offers they receive.Higher first-offer acceptance → fewer cascade hops, faster assignment.
vehicle_fitHow well the vehicle matches the job (not oversized).A bike for documents beats a Bolero — right-sizing minimizes cost per parcel.
trust_tierGraduated trust level from KYC + track record.Gates eligibility for high-value/long jobs; reduces fraud/loss exposure.
fairness_rotationRecent income/job share for this partner.Spreads work, retains partners, prevents starvation (see §7).
green_bonusCycle / e-rickshaw / EV preference.Lower-emission and often lower-cost legs for short urban hops.
Trust tier is a gate, not just a weight. A new partner with a high proximity score is still ineligible for high-value, long-distance, or pay-on-delivery jobs — early-stage partners are restricted to low-value, short, prepaid bookings until they graduate. Eligibility is checked before the score is ever computed; see the graduated trust ladder in Onboarding & KYC.

5. Dispatch flow & cascade

Once a booking is ESCROW_HELD / paid, the matching engine runs the dispatch loop: query nearby eligible partners, score and rank them, offer to the top candidate, and cascade to the next on decline or timeout. If the cascade exhausts every option, the booking moves to NO_PARTNER_FOUND and the held escrow is auto-refunded.

sequenceDiagram
  autonumber
  participant GW as "Go booking API"
  participant MA as "Matching engine"
  participant GEO as "PostGIS + Redis GEOSEARCH"
  participant PT1 as "Partner (rank 1)"
  participant PT2 as "Partner (rank 2)"
  participant PAY as "Payments + escrow"
  participant U as "Booker"
  GW->>MA: "Booking PAID — dispatch"
  MA->>GEO: "Nearest eligible partners (radius, vehicle class)"
  GEO-->>MA: "Candidate list"
  MA->>MA: "Score & rank (proximity, rating, fairness, fit)"
  MA->>PT1: "Offer (auto-assign default OR accept within N s)"
  alt Accepts in time
    PT1-->>MA: "Accept"
    MA-->>U: "Assigned partner + ETA"
  else Declines or times out
    PT1-->>MA: "Decline / timeout"
    MA->>PT2: "Cascade: offer to next ranked"
    PT2-->>MA: "Accept"
    MA-->>U: "Assigned partner + ETA"
  else Cascade exhausted
    MA->>GEO: "Widen radius / check milk-run schedule"
    GEO-->>MA: "Still none"
    MA->>PAY: "NO_PARTNER_FOUND → auto-refund escrow"
    PAY-->>U: "Full refund + notify"
  end
        
Dispatch sequence: a nearest-eligible geo query feeds scoring; the top partner is offered the job with an accept-within-N-seconds (or auto-assign default) window; decline/timeout cascades down the ranked list; exhaustion widens the radius then falls to NO_PARTNER_FOUND with an automatic full refund (see Payments).
Money safety: matching never silently drops a paid booking. If no partner can be found after widening and checking milk-run schedules, the engine emits NO_PARTNER_FOUND → REFUNDED so the booker is made whole automatically. The platform holds no money, so the refund is a gateway reversal — see Payments & Integration.

6. Bundling logic

Bundling is what makes the milk-run cheap. The engine decides two or more parcels can share a trip only when direction, capacity and time windows all line up, then batch-assigns the group to one partner or one scheduled milk-run.

Compatibility checkRule
Same directionPickups and drops fall along a shared corridor / toward the same village cluster — no large detours.
Capacity fitsCombined weight & volume stay within the chosen vehicle's class limit (the eligibility check, summed).
Time windows compatibleEvery parcel's delivery window can still be met given the batched stop sequence; perishables tighten this.
Handling compatibleNo conflicting flags (e.g. cold-chain not mixed with non-cold; fragile stacked safely).
flowchart TB
  P["New eligible parcel"] --> DIR{"Same direction as
an open bundle?"} DIR -- "no" --> NEW["Seed new milk-run / on-demand"] DIR -- "yes" --> CAP{"Capacity still fits?"} CAP -- "no" --> NEW CAP -- "yes" --> WIN{"Time windows
compatible?"} WIN -- "no" --> SPLIT["Split batch / new bundle"] WIN -- "yes" --> ADD["Add to bundle"] ADD --> ASSIGN["Batch-assign to one
partner / milk-run"]
Bundling decision: a candidate parcel joins an open bundle only if direction, capacity and time windows all hold; otherwise it seeds a new bundle or splits the batch. The batch is then assigned as a unit to one partner or milk-run.
The stop order within a bundle is a Vehicle Routing Problem solved in Fastest-Route Finding; the cost savings from batching feed the unit-economics model in Scale & Low-Cost.

7. Fairness rotation

A pure cost-minimizer would funnel every job to the same handful of top-rated, perfectly-placed partners and starve everyone else. RideChain treats partner retention and rural livelihood as first-class goals, so fairness enters the score directly as the fairness_rotation term: a partner who has recently earned little or been offered few jobs gets a positive boost, nudging work their way when they are otherwise competitive.

flowchart LR
  RAW["Raw cost-aware rank"] --> ADJ["Apply fairness boost
(low recent income / few offers)"] ADJ --> CAP{"Anti-monopoly cap
reached for top partner?"} CAP -- "yes" --> NEXT["Prefer next eligible partner"] CAP -- "no" --> KEEP["Keep ranked order"] NEXT --> OUT["Final offer order"] KEEP --> OUT
Fairness rotation layered on the cost rank: a boost lifts under-served partners, and an anti-monopoly cap prevents any single partner from hogging a market's volume. Efficiency still bounds it — fairness only reorders among already-eligible, reasonably-competitive candidates.
Fair, not blind. Fairness avoids starving low-rated partners entirely — they still receive offers they are eligible for — but it never forces an unsafe or wildly-detoured assignment. It is a tie-and-near-tie breaker plus a safety floor, not an override of capacity or trust gates.

8. Relay leg assignment

A relay (Mode B) booking decomposes into ordered legs — first-mile, hub-to-hub, last-mile. Matching treats each leg as its own job: every leg is independently filtered, scored and assigned to a partner whose coverage and vehicle suit that segment. A bike may win the first-mile pickup while a Tata Ace wins the hub-to-hub haul and an e-rickshaw the village last-mile.

flowchart LR
  S["Sender / origin Point"] -->|"leg 1 · first-mile"| PA["Partner A (matched for leg 1)"]
  PA -->|"handover at hub"| HUB["🏬 Block Hub
consolidate"] HUB -->|"leg 2 · matched independently"| PB["Partner B (matched for leg 2)"] PB -->|"leg 3 · last-mile, matched"| R["Receiver / dest Point"] classDef hub fill:#fff3e0,stroke:#f4920b,color:#8a5200; class HUB hub;
Each relay leg is matched on its own: the engine picks the best partner for the first-mile, a separate partner for the hub leg, and another for the last-mile. The hub is the custody pivot between independently-assigned partners.

Because each leg is a separate assignment, each leg also carries a separate custody lock and a separate money slice. The custody chain across legs (assignment lock + parcel-QR + dual-OTP + geofence) is documented in Last-Mile Delivery, and the per-leg payout — released on that leg's handover — in Split-Money Settlement. If leg 2 cannot be matched immediately, the parcel simply waits in hub custody and is re-matched, without disturbing the already-completed leg 1.

9. Edge cases & failure modes

Matching assumes the unhappy path is routine: partners decline, go offline, GPS drifts, and the same job risks being offered to a crowd. Each risk below has a defined mitigation; the full catalogue lives in the Edge-Case Catalog.

ScenarioMitigation
No eligible partner onlineWiden the search radius progressively → check the milk-run schedule for a later bundle → if still none, NO_PARTNER_FOUND and auto-refund the escrow.
All ranked partners declineCascade through the full ranked list; apply a surge bump to make the job more attractive and notify a wider pool before declaring no-partner.
Partner goes offline after acceptingAuto re-dispatch from MATCHING to the next candidate; apply a partner reliability penalty; booker not charged for the drop.
Stale GPS makes "nearest" wrongEnforce a location-accuracy / freshness threshold; ignore stale fixes and recompute the nearest set on a fresh ping (see Geolocation).
Thundering herd — one job offered to manySingle-offer model with an assignment lock in Redis; only one partner holds the offer at a time, preventing duplicate accepts.
Over-capacity partner accepts too muchCapacity check at accept time (current load + this parcel vs vehicle limit); reject the accept and cascade if it would overflow.
Relay leg-2 unmatched at hubHold the parcel in hub custody, pause the leg SLA clock, and re-match leg 2 on a timer; leg 1 stays paid.
New partner offered a high-value jobTrust gate blocks it — new partners are eligible only for low-value, short, prepaid jobs until graduated (KYC tiers).
Bundling time-window conflictIf a parcel's window can no longer be met inside a batch, split the batch and re-seed a faster bundle or on-demand offer.
Fairness vs efficiency tradeoffFairness boost is bounded — it only reorders among already-eligible, near-tie candidates and never forces an unsafe or wildly-detoured assignment.
Vehicle mismatch discovered at pickupRe-match to an eligible larger class (or upcharge per policy) rather than forcing an unsafe load; original offer voided.
Spoofed location to grab nearby jobsMock-location / fraud flag on the partner; offers suppressed pending review; cross-checked against the accuracy signals in Geolocation.