Booking & Delivery Flow
From "I want to send a parcel" to "delivered, money settled" β the entry points, modes, state machine, OTP/POD custody chain, relay journeys, refunds, and the no-smartphone path.
1. Overview & the two entry points
A RideChain booking can begin in two completely different places, and the most important thing to understand up front is this: you do not need to walk into a RideChain Point to book. The overwhelming majority of bookings are self-serve from a phone. A "Point" is a physical handover venue (and a fallback for people without a smartphone), not a booking counter you must visit.
Entry A β Digital self-serve
The booker creates the order on their own device: the Book app (Flutter), the Next.js PWA on the web, the WhatsApp bot, or an IVR / missed-call callback. No travel needed β quote, pay and track all happen on the phone.
Entry B β Walk-in at a Point
A customer with no smartphone (or who simply wants help) walks into a RideChain Point β a kirana, CSC, panchayat office or chai stall β and the operator books on the customer's behalf using the assisted-booking screen. The Point is also where a parcel is physically dropped off or collected.
POINT drop is common; walking into a Point to book is the exception, used mainly for the no-smartphone segment.
flowchart TB
subgraph Digital["Entry A Β· Digital self-serve (phone, no travel)"]
BA["π± Book app (Flutter)"]
WEB["π» Next.js PWA (web)"]
WAB["π¬ WhatsApp bot"]
IVR["π IVR / missed-call"]
end
subgraph Assisted["Entry B Β· Walk-in at a RideChain Point"]
OP["π§βπΌ Kirana / CSC operator
books on customer's behalf"]
end
BA & WEB & WAB & IVR --> API["Go booking API"]
OP --> API
API --> SM["Booking state machine
(DRAFT β QUOTED β β¦ β SETTLED)"]
classDef d fill:#e8f0fb,stroke:#1f5fae,color:#143d6e;
classDef a fill:#fff3e0,stroke:#f4920b,color:#8a5200;
class BA,WEB,WAB,IVR d; class OP a;
2. Pickup & drop modes (DOOR vs POINT)
At booking time the booker chooses a pickup mode and a drop mode, each independently DOOR or POINT. These four combinations are the single biggest lever on price and speed: a door visit is dedicated partner time (premium), while a Point lets the parcel ride a shared, batched milk-run (cheapest).
| Pickup β Drop | What it means | Cost | Best speed tier |
|---|---|---|---|
DOOR β DOOR | Partner collects from the sender's house and hands to the receiver's house. Two dedicated visits, no Point staging. | Premium (highest) | Urgent / on-demand |
DOOR β POINT | Partner picks up at the sender's door; parcel rests at the destination Point for the receiver to collect. | Mid | Express |
POINT β DOOR | Sender drops at a nearby Point; a partner delivers the last leg to the receiver's door. | Mid | Express |
POINT β POINT | Sender drops at origin Point; parcel rides a bundled milk-run to the destination Point for pickup. No door visit at all. | Cheapest (bundled) | Bundled milk-run (slowest, cheapest) |
POINT β POINT is cheapest: the parcel is consolidated with others at the Block Hub and moves on a shared route. No partner spends dedicated minutes finding a house. DOOR pickup carries a premium because it is dedicated, single-parcel partner time.Speed tiers map onto modes: Urgent / on-demand wants a dedicated partner (favours DOOR ends); Express mixes a dedicated leg with a Point; Bundled milk-run requires POINT β POINT so the parcel can be batched. See Commission & Pricing for the fare formula and surge.
3. The booking creation flow
Creation walks the booker through five inputs, produces a live quote, takes payment into escrow, then matches a partner. Pricing, payment and matching are separate idempotent steps β none assumes a single happy reply, and payment is only confirmed by the PG webhook, never by the client's own "I paid" message.
- Choose pickup & drop modes β
DOOR/POINTfor each end, with addresses or a Point picked from the map. - Describe the package β category, size bucket (
S/M/L/XL), weight bucket, and flags:fragile,perishable,urgent,oversized. - Engine recommends a vehicle β from size/weight/flags/geo; the booker may override (e.g. force a Bolero for a bulky item).
- Live price quote β pricing returns fare + breakdown for the chosen tier; re-quoted if any input changes.
- Pay into escrow β a gateway order is created (Razorpay primary β Cashfree fallback); funds are held, the platform holds no money.
- Match & assign β bundling-first, then on-demand cascade; the booker receives the assigned partner + ETA and live tracking begins.
sequenceDiagram
autonumber
participant U as "Booker (app / web / WA / operator)"
participant GW as "Go booking API"
participant PR as Pricing
participant PAY as "Payments + escrow"
participant PG as "Gateway (RZP β CF)"
participant MA as Matching
participant PT as "Partner app"
U->>GW: "Choose pickup/drop modes + addresses"
U->>GW: "Package: category, size S/M/L/XL, weight, flags"
GW->>PR: "Recommend vehicle (size, weight, flags, geo)"
PR-->>U: "Suggested vehicle (user may override)"
U->>GW: "Confirm vehicle + speed tier"
GW->>PR: "quote(modes, vehicle, tier, geo)"
PR-->>U: "Live price + breakdown"
U->>GW: "Confirm + place booking (idempotency-key)"
GW->>PAY: "Create escrow order"
PAY->>PG: "Order (Razorpay, fallback Cashfree)"
PG-->>U: "Payment intent (UPI / wallet)"
U->>PG: "Pay"
PG-->>PAY: "WEBHOOK: captured (source of truth)"
PAY-->>GW: "Escrow held (idempotent)"
GW->>MA: "Dispatch (bundling-first β on-demand)"
MA->>PT: "Offer leg(s)"
PT-->>MA: "Accept"
MA-->>U: "Assigned partner + ETA, live track begins"
4. The booking state machine
A booking is a finite state machine. The happy path threads from DRAFT to SETTLED; every off-ramp (no partner, cancellation, failed handover, dispute) is an explicit side state with defined money behaviour. Relay bookings loop through AT_HUB once per intermediate leg.
stateDiagram-v2
[*] --> DRAFT
DRAFT --> QUOTED: "price returned"
QUOTED --> PAYMENT_PENDING: "place booking"
PAYMENT_PENDING --> ESCROW_HELD: "PG webhook captured"
PAYMENT_PENDING --> CANCELLED_BY_BOOKER: "abandon / timeout"
ESCROW_HELD --> MATCHING: "dispatch"
MATCHING --> ASSIGNED: "partner accepts"
MATCHING --> NO_PARTNER_FOUND: "cascade exhausted"
NO_PARTNER_FOUND --> REFUNDED: "auto-refund escrow"
ASSIGNED --> EN_ROUTE_PICKUP: "partner moving"
ASSIGNED --> CANCELLED_BY_PARTNER: "partner drops"
EN_ROUTE_PICKUP --> AT_PICKUP: "geofence reached"
AT_PICKUP --> PICKED_UP: "pickup OTP verified"
AT_PICKUP --> FAILED_PICKUP: "sender absent / refused"
PICKED_UP --> IN_TRANSIT
IN_TRANSIT --> AT_HUB: "relay leg"
AT_HUB --> IN_TRANSIT: "next leg assigned"
IN_TRANSIT --> AT_DROP: "final leg geofence"
AT_DROP --> DELIVERED: "drop OTP + POD"
AT_DROP --> FAILED_DELIVERY: "receiver absent"
FAILED_DELIVERY --> RETURNED: "reverse logistics"
DELIVERED --> SETTLED: "escrow released, splits paid"
CANCELLED_BY_BOOKER --> REFUNDED
CANCELLED_BY_PARTNER --> MATCHING: "re-dispatch"
FAILED_PICKUP --> REFUNDED
DELIVERED --> DISPUTED: "complaint window"
DISPUTED --> SETTLED: "resolved in favour of partner"
DISPUTED --> REFUNDED: "resolved in favour of booker"
RETURNED --> REFUNDED
SETTLED --> [*]
REFUNDED --> [*]
DRAFT β QUOTED β PAYMENT_PENDING β ESCROW_HELD β MATCHING β ASSIGNED β EN_ROUTE_PICKUP β AT_PICKUP β PICKED_UP β IN_TRANSIT β (AT_HUB loop) β AT_DROP β DELIVERED β SETTLED. Side states cover no-partner, both-side cancellation, failed pickup/delivery, returns, disputes and refunds.ESCROW_HELD is the pivot. Before it, money is the booker's and a cancel is a clean refund. After it, money is committed and release follows handover. Each completed leg releases its slice on its own handover β see Split-Money Settlement.5. OTP & POD handover
RideChain uses four OTPs across a booking, each closing a specific trust gap, plus a geo- and time-stamped Proof-of-Delivery photo and a tamper-evident QR on the parcel.
| OTP | Who proves it | What it unlocks |
|---|---|---|
| Booking OTP | Booker (phone) | Confirms the booker's number / consent to place the order. |
| Pickup OTP | Sender β partner | Sender reads the code; partner enters it to prove the right parcel was collected from the right person. |
| Drop OTP | Receiver β partner | Receiver reads the code; partner enters it. This is what releases the leg's escrow. |
| Payment OTP | Booker | Bank/UPI step-up during pay-in; owned by the gateway, surfaced in our flow. |
On top of OTPs, every handover records a POD photo stamped with GPS + timestamp (stored in Cloudflare R2) and a QR scan of the parcel's unique ID. The QR scan must match the assigned parcel or the app blocks the handover β this is what stops a wrong parcel being given out.
flowchart LR
A["Partner reaches drop geofence"] --> B{"Scan parcel QR"}
B -- "mismatch" --> X["Block: wrong parcel"]
B -- "match" --> C["Receiver reads drop OTP"]
C --> D{"OTP correct?"}
D -- "no" --> R["Retry / fallback channel"]
D -- "yes" --> E["Capture POD photo (GPS + time)"]
E --> F["Mark DELIVERED β release leg escrow"]
6. Delivery journey β direct vs relay
A booking decomposes into ordered legs. A direct booking (Mode A) is one leg, one partner, door-to-door or Point-to-door. A relay / milk-run booking (Mode B) is multiple legs that pass through a Block Hub for consolidation, each leg a different partner. Money splits per leg, and each leg releases on its own handover.
flowchart TB
subgraph ModeA["Mode A Β· Direct (one leg)"]
SA["Sender"] -->|"pickup OTP"| PA["Partner A"]
PA -->|"drop OTP + POD"| RA["Receiver"]
end
subgraph ModeB["Mode B Β· Relay / milk-run (multi-leg via Hub)"]
SB["Sender / origin Point"] -->|"pickup OTP, leg 1"| PB1["Partner A"]
PB1 -->|"handover at hub"| HUB["π¬ Block Hub
consolidate"]
HUB -->|"leg 2 assigned"| PB2["Partner B"]
PB2 -->|"drop OTP + POD, leg 2"| RB["Receiver / dest Point"]
end
classDef hub fill:#fff3e0,stroke:#f4920b,color:#8a5200;
class HUB hub;
The custody chain holds each parcel to exactly one partner per leg via four interlocking controls: an assignment lock, the unique parcel-ID / QR scan, the two-sided handover OTP, and a geofence + timestamp. A partner may serve many Points (coverage), but a given parcel is locked to one Point + one partner per leg.
| Example | Leg split (per _CONVENTIONS) |
|---|---|
| Single point-to-point, total βΉ120 | Partner βΉ80 Β· drop Point βΉ6 Β· collect Point βΉ6 Β· platform βΉ28 (absorbs PG ~βΉ2.4 + tax reserve ~βΉ3 β net ~βΉ22.6) |
| Relay, total βΉ220 | Partner A leg1 βΉ55 Β· Partner B leg2 βΉ95 Β· drop Point βΉ6 Β· hub βΉ8 Β· collect Point βΉ6 Β· platform βΉ50 |
7. Cancellation, failed pickup/delivery, returns & refunds
Who can cancel β and at what cost β depends on the state at the moment of cancellation. The rule of thumb: before ESCROW_HELD, cancels are free/full-refund; after a partner has started or completed work, work already done is paid for.
| State at cancel | Who can cancel | Fee / escrow outcome |
|---|---|---|
DRAFT / QUOTED | Booker | Free β no money taken yet. |
PAYMENT_PENDING | Booker (or timeout) | Order voided; nothing captured β full refund of any auth. |
ESCROW_HELD / MATCHING | Booker | Full refund (no partner committed yet). |
ASSIGNED / EN_ROUTE_PICKUP | Booker | Small cancellation fee to compensate partner travel; remainder refunded. |
ASSIGNED / mid-leg | Partner | Auto re-dispatch (back to MATCHING); a completed prior leg is still paid; booker not penalised. |
AT_PICKUP β FAILED_PICKUP | System | Sender absent/refused after retries β refund minus any travel fee. |
AT_DROP β FAILED_DELIVERY | System | Receiver absent β fall back to nearest Point or move to RETURNED. |
RETURNED | System | Reverse-logistics leg back to sender/origin Point; return leg charged or absorbed per policy, then REFUNDED for the undelivered portion. |
Reverse logistics: a return creates a new leg in the opposite direction (receiver/drop-Point β sender/origin-Point), re-using the same custody controls. The partner who carries the return leg is paid for it; the booker is refunded the value of the service not rendered (delivery), net of any return-leg charge.
8. No-app & low-literacy support
Rural reach means many bookers have no smartphone, intermittent data, or low literacy. The flow degrades gracefully across channels and reading levels.
WhatsApp & IVR
A WhatsApp bot walks through modes/package/quote in a chat; an IVR / missed-call flow calls the user back and books by voice prompts. Both produce the same DRAFT β β¦ β SETTLED booking.
Assisted booking at a Point
The kirana/CSC operator uses a simplified screen to book for a walk-in customer, prints/sticks the parcel QR, and stages the parcel for pickup or hands over a collection.
Voice & icon UI
Hindi-first, vernacular + audio prompts; icon- and photo-led screens so size/category can be chosen without reading. OTPs are read aloud where needed.
Offline outbox & sync
The Book/Partner apps queue the booking action in a local outbox (Drift/SQLite) when offline and replay it on reconnect β keyed by idempotency-key so a replay never double-books.
9. Edge cases & failure modes
The booking flow is built assuming the unhappy path is the common path. Each risk below has a defined mitigation; the full catalogue lives in the Edge-Case Catalog.
| Scenario | Mitigation |
|---|---|
| OTP not received (SMS down / no signal) | Fallback channels: WhatsApp β IVR voice readout β in-app display β operator-assisted re-send. |
Receiver absent at a DOOR drop | Auto-fallback to nearest RideChain Point for collection; booker notified; else move to FAILED_DELIVERY β RETURNED. |
| Partner cancels mid-leg | Re-dispatch from MATCHING; any already-completed leg stays paid; booker not penalised, journey resumes. |
Payment captured but matching fails (NO_PARTNER_FOUND) | Auto-refund the held escrow in full; booking moves NO_PARTNER_FOUND β REFUNDED. |
| Double-tap / duplicate booking | Idempotency-key on "place booking"; the second request returns the existing booking, never a second order or charge. |
| GPS denied / spoofed at pickup geofence | Block auto-confirm; require operator/manual confirm + photo; fraud module flags mock-location. |
| Wrong parcel handed over | QR scan must match the assigned parcel-ID or the app blocks the handover β no OTP prompt, no release. |
| Perishable / urgent parcel delayed | Perishable flag tightens SLA and routing priority; breach triggers proactive notify + partial-refund / re-route policy. |
| Declared-value dispute on damage/loss | Declared value is recorded at booking; claims reconcile against it via the dispute flow (DELIVERED β DISPUTED). |
| Network drop during booking | Local outbox persists the action; replays on reconnect, deduped by idempotency-key; webhook reconciles payment. |
| Relay second-leg partner never picks up at hub | Hub holds custody; leg-2 re-dispatched after timeout; SLA clock paused; booker kept informed. |
| Webhook lost / delayed after capture | Reconciliation job polls the gateway; idempotent escrow-held event prevents double-processing when the webhook later arrives. |