mobility.book_two_wheeler_rental — Full Intent Specification
INTENT NAMESPACE: mobility
INTENT NAME: book_two_wheeler_rental
FULL ID: mobility.book_two_wheeler_rental
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-10
TTBS WEIGHTS: time 0.20 · taste 0.20 · budget 0.30 · safety 0.30
Two-wheeler rental shares the self-drive doctrine (user IS the rider) with three locked differences: (a) helmet provisioning is a first-class field — partners MUST provide certified helmets; (b) license endorsement gate is license_endorsement_2w (often missing on Indian DLs that only cover LMV); (c) safety telemetry is critical — 2W riders are high-injury cohort, so partner-side helmet_strap_sensor and gear-provisioning rank heavily.
1. NATURAL LANGUAGE COVERAGE
Classifies IN
- "rent scooter for the day"
- "Activa rental Hyderabad"
- "rent bike for weekend"
- "Royal Enfield rental Goa"
- "Yulu scooter to office"
- "rent EV scooter for the day"
- "two wheeler rental near me"
- "Bounce scooter for 2 hours"
- "rent geared bike for highway ride"
Classifies OUT — borderline NO
- "Rapido bike taxi to MG Road" →
mobility.book_intracity_ride(bike_taxi vehicle_kind) - "self-drive car for weekend" →
mobility.book_self_drive - "I want to buy a scooter" → no intent (informational)
- "service my bike" →
auto.book_general_service - "auto to airport" →
mobility.book_intracity_ride
MULTI-INTENT TRIGGERS
- "rent scooter for the day and book hotel near city centre" →
mobility.book_two_wheeler_rental+travel.book_hotel - "rent bike for highway ride and verify my DL" →
mobility.book_two_wheeler_rental+compliance.verify_rc_dl - "rent EV scooter and check charge stations along route" →
mobility.book_two_wheeler_rental+mobility.book_ev_with_charge_planning
2. INPUT — TOMO → PROVIDER
{
"intent": "mobility.book_two_wheeler_rental",
"intent_version": "v1.0.0",
"request_id": "req_2w_5h7m_2026-05-10T07:30:00Z",
"user_session_id": "anon_user_token_or_uid",
"pickup_location": {
"lat": 17.4435,
"lng": 78.3772,
"address": "Bounce Hub Madhapur",
"neighborhood": "Madhapur",
"city": "Hyderabad",
"pincode": "500081",
"state_code": "TS",
"country_code": "IN",
"hub_kind": "branded_hub",
"instructions": "Outside metro station gate B"
},
"drop_location": {
"lat": 17.4435,
"lng": 78.3772,
"address": "Bounce Hub Madhapur",
"neighborhood": "Madhapur",
"city": "Hyderabad",
"pincode": "500081",
"state_code": "TS",
"country_code": "IN",
"hub_kind": "branded_hub",
"instructions": "Same hub return"
},
"rental_kind": "round_trip",
"scheduled_pickup_iso": "2026-05-10T09:00:00+05:30",
"scheduled_return_iso": "2026-05-10T18:00:00+05:30",
"billed_hours": 9,
"billed_days": 0,
"user_riding_profile": {
"user_age": 28,
"license_state_code": "TS",
"license_endorsement_2w": true,
"license_endorsement_2w_with_gear": true,
"license_held_for_years": 6,
"license_verified_with_partner": false,
"prior_2w_rental_count": 7,
"international_license": false
},
"preferences": {
"vehicle_kinds_acceptable": ["scooter", "electric_scooter"],
"engine_cc_max": 125,
"fuel_kinds_acceptable": ["petrol", "ev_full"],
"budget_band": "ok",
"budget_max_inr": 350,
"min_pillion_capacity": 1,
"doorstep_delivery_required": false,
"with_fuel_topped": true,
"include_pillion_helmet": true,
"include_raincoat": true,
"include_jacket": false
},
"trip_intent": {
"expected_distance_km": 40,
"expected_states_crossed": ["TS"],
"involves_highway": false,
"is_overnight": false,
"is_late_night_pickup": false,
"purpose": "commute_to_office"
},
"context": {
"user_locale": "en-IN",
"user_currency_pref": "INR",
"trust_signals": {
"is_repeat_customer": true,
"prior_rentals_with_partner": 3,
"user_account_age_days": 312
}
}
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, equals "mobility.book_two_wheeler_rental" |
|
pickup_location.hub_kind |
enum | REQUIRED, see §5 | |
rental_kind |
enum | REQUIRED, STRICT round_trip | one_way |
|
billed_hours |
int | REQUIRED, ≥1 | hourly billing common for 2W |
user_riding_profile.user_age |
int | REQUIRED, ≥18 | |
user_riding_profile.license_endorsement_2w |
bool | REQUIRED | HARD FILTER if false |
user_riding_profile.license_endorsement_2w_with_gear |
bool | REQUIRED | required for geared bikes |
preferences.vehicle_kinds_acceptable |
array |
REQUIRED, ≥1 | |
preferences.engine_cc_max |
int | REQUIRED, ≥0 | 0 means EV/no-CC; ≥350 for premium bikes |
preferences.min_pillion_capacity |
int | REQUIRED, ≥0 | 0 = solo OK |
preferences.include_pillion_helmet |
bool | REQUIRED | drives helmet count |
preferences.include_raincoat |
bool | REQUIRED | seasonal |
preferences.include_jacket |
bool | REQUIRED | premium-bike rentals |
trip_intent.involves_highway |
bool | REQUIRED | most 2W rentals city-only |
Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.
3. PROVIDER TOOLS
Tool 1: get_two_wheeler_inventory
PURPOSE: return available 2W vehicles for the requested window + location
INPUT: §2 request body
OUTPUT: { options: TwoWheelerOption[], result_token, expires_at }
SLA: p50 < 600ms, p95 < 1500ms
RATE LIMIT: ≤ 1/sec per user
Tool 2: book_two_wheeler
PURPOSE: commit a 2W reservation
INPUT: { option_id, payment_token, request_id, idempotency_key, user_phone, dl_image_url, selfie_image_url, deposit_token }
OUTPUT: { booking_ref, status, vehicle, fare_quote, deposit_inr, hub_handover_window_iso, gear_kit }
SLA: p95 < 4000ms
IDEMPOTENCY: REQUIRED on idempotency_key
Tool 3: get_handover_state
PURPOSE: live booking + handover state
INPUT: { booking_ref, request_id }
OUTPUT: TwoWheelerHandoverState (§4)
SLA: p95 < 500ms
RATE LIMIT: ≤ 1 every 30s
Tool 4: cancel_two_wheeler
PURPOSE: cancel
INPUT: { booking_ref, reason, request_id }
OUTPUT: { status, cancellation_charge_inr, refund_amount_inr, refund_processing_days }
SLA: p95 < 2000ms
Tool 5: extend_two_wheeler
PURPOSE: extend rental return time
INPUT: { booking_ref, new_return_iso, request_id }
OUTPUT: { revised_fare_inr, additional_hours_billed, status }
SLA: p95 < 1500ms
Tool 6: report_damage_or_incident
PURPOSE: user reports incident mid-rental
INPUT: { booking_ref, incident_kind, photos[], description, request_id }
OUTPUT: { incident_ref, status, partner_action_taken }
SLA: p95 < 2000ms
Tool 7: complete_return
PURPOSE: partner records return + condition photos + final fare
INPUT: { booking_ref, return_photos[], odometer_reading_km, fuel_level, helmet_returned_count, request_id }
OUTPUT: { final_fare_inr, deposit_refund_inr, damage_charge_inr, helmet_loss_charge_inr, late_return_charge_inr, status }
SLA: p95 < 3000ms
All seven REQUIRED.
4. RESPONSE SHAPE
TwoWheelerOption (returned by get_two_wheeler_inventory)
id: string, REQUIRED
option_token: string, REQUIRED
expires_at: ISO_DATETIME, REQUIRED
vehicle_kind: STRICT ENUM, REQUIRED # see §5
vehicle_class: STRICT ENUM, REQUIRED
display_label: string, REQUIRED # "Honda Activa 6G"
make: string, REQUIRED
model: string, REQUIRED
variant: string, REQUIRED
year_of_manufacture: int, REQUIRED
engine_cc: int, REQUIRED, ≥0 # 0 if EV
pillion_capacity: int, REQUIRED, 0 or 1 # 1 for most 2W; 0 for kick-only racing
storage_under_seat_litres: float, REQUIRED, ≥0
availability:
pickup_hub_address: string, REQUIRED
pickup_hub_lat: float, REQUIRED
pickup_hub_lng: float, REQUIRED
pickup_hub_kind: STRICT ENUM, REQUIRED
doorstep_delivery_available: boolean, REQUIRED
doorstep_delivery_charge_inr: INR_INTEGER, REQUIRED
hub_open_iso: ISO_DATETIME, REQUIRED
hub_close_iso: ISO_DATETIME, REQUIRED
vehicle_ready_at_iso: ISO_DATETIME, REQUIRED
alternate_pickup_hubs: array, REQUIRED, may be empty
fare:
total_inr: INR_INTEGER, REQUIRED
base_per_hour_inr: INR_INTEGER, REQUIRED
base_per_day_inr: INR_INTEGER, REQUIRED
billed_hours: int, REQUIRED
billed_days: int, REQUIRED
included_km: int, REQUIRED
per_km_overage_inr: float, REQUIRED
fuel_policy: STRICT ENUM, REQUIRED
fuel_top_up_charge_inr: INR_INTEGER, REQUIRED
basic_insurance_inr: INR_INTEGER, REQUIRED
helmet_inr: INR_INTEGER, REQUIRED # 0 if free
pillion_helmet_inr: INR_INTEGER, REQUIRED # 0 if not requested
raincoat_inr: INR_INTEGER, REQUIRED
jacket_inr: INR_INTEGER, REQUIRED
panniers_inr: INR_INTEGER, REQUIRED # 0 if not requested
late_return_per_hour_inr: INR_INTEGER, REQUIRED
doorstep_delivery_inr: INR_INTEGER, REQUIRED
one_way_drop_charge_inr: INR_INTEGER, REQUIRED
platform_fee_inr: INR_INTEGER, REQUIRED
gst_inr: INR_INTEGER, REQUIRED
fare_breakdown_text: string, REQUIRED
is_upfront_fare: boolean, REQUIRED
fare_locked_until_iso: ISO_DATETIME, REQUIRED
deposit:
required: boolean, REQUIRED
amount_inr: INR_INTEGER, REQUIRED
hold_kind: STRICT ENUM, REQUIRED
refund_eta_business_days: int, REQUIRED, ≥0
gear_kit:
rider_helmet_provided: boolean, REQUIRED
rider_helmet_isi_certified: boolean, REQUIRED
rider_helmet_size_options: array<STRICT ENUM>, REQUIRED # see §5
pillion_helmet_provided: boolean, REQUIRED
pillion_helmet_isi_certified: boolean, REQUIRED
raincoat_provided: boolean, REQUIRED
jacket_provided: boolean, REQUIRED
jacket_with_armor: boolean, REQUIRED
panniers_provided: boolean, REQUIRED
knee_guards_provided: boolean, REQUIRED
gloves_provided: boolean, REQUIRED
vehicle_meta:
age_years: int, REQUIRED
fuel_kind: STRICT ENUM, REQUIRED
fuel_efficiency_kmpl: float, REQUIRED
fuel_tank_capacity_litres: float, REQUIRED
ev_battery_charge_pct: int, REQUIRED, 0-100
ev_range_km_remaining: int, REQUIRED
emission_norm: STRICT ENUM, REQUIRED
registration_state_code: string, REQUIRED
vehicle_class_certification: STRICT ENUM, REQUIRED # private | self_drive_yellow_plate
comprehensive_insurance: boolean, REQUIRED
insurance_valid_until_iso: ISO_DATE, REQUIRED
insurance_company: string, REQUIRED
fitness_certificate_valid_until_iso: ISO_DATE, REQUIRED
puc_valid_until_iso: ISO_DATE, REQUIRED
permit_kind: STRICT ENUM, REQUIRED # self_drive_permit
vehicle_color: string, REQUIRED
last_serviced_iso: ISO_DATE, REQUIRED
odometer_reading_km: int, REQUIRED, ≥0
current_fuel_level_pct: int, REQUIRED, 0-100
geofence_kind: STRICT ENUM, REQUIRED
geofence_states_allowed: array<string>, REQUIRED, ≥1
speed_limit_governed: boolean, REQUIRED
speed_limit_kmph: int, REQUIRED
telematics_active: boolean, REQUIRED
helmet_strap_sensor: boolean, REQUIRED # detects unhelmeted riding
abs: boolean, REQUIRED
cbs: boolean, REQUIRED # combined braking system
vehicle_amenities:
led_headlight: boolean, REQUIRED
digital_cluster: boolean, REQUIRED
bluetooth_console: boolean, REQUIRED
usb_charger: boolean, REQUIRED
glove_box: boolean, REQUIRED
side_stand_indicator: boolean, REQUIRED
vehicle_photos:
pre_handover_photos_required: boolean, REQUIRED
pre_handover_photos: array<URL>, REQUIRED # ≥4 angles for 2W
pre_handover_photos_iso: ISO_DATETIME, REQUIRED
damage_marker_present_at_pickup: boolean, REQUIRED
rider_qualification_for_user:
min_user_age_required: int, REQUIRED, ≥18
min_license_held_years: int, REQUIRED, ≥0
geared_endorsement_required: boolean, REQUIRED
international_license_accepted: boolean, REQUIRED
user_meets_qualification: boolean, REQUIRED
qualification_failure_reason: STRICT ENUM, REQUIRED
partner_safety_features:
sos_button_in_app: boolean, REQUIRED
trip_share_supported: boolean, REQUIRED
in_app_chat_support: boolean, REQUIRED
in_app_call_support: boolean, REQUIRED
emergency_contact_alerts: boolean, REQUIRED
vehicle_telematics_alerts: boolean, REQUIRED
roadside_assistance_24x7: boolean, REQUIRED
on_call_mechanic: boolean, REQUIRED
emergency_swap_vehicle: boolean, REQUIRED
helmet_verification_at_pickup: boolean, REQUIRED # partner verifies user wears helmet
cancellation:
free_cancel_until_iso: ISO_DATETIME, REQUIRED
cancel_charge_within_24h_inr: INR_INTEGER, REQUIRED
cancel_charge_within_2h_inr: INR_INTEGER, REQUIRED
no_show_charge_inr: INR_INTEGER, REQUIRED
partner_cancel_compensation_inr: INR_INTEGER, REQUIRED
refund_processing_days: int, REQUIRED, ≥0
freshness:
data_last_synced_iso: ISO_DATETIME, REQUIRED
_provider:
name: string, REQUIRED
tomo_partner_id: string, REQUIRED
partner_tier: STRICT ENUM, REQUIRED
deep_link: URL, REQUIRED
customer_support_phone: string, REQUIRED
customer_support_24x7: boolean, REQUIRED
partner_2w_volume_30d: int, REQUIRED, ≥0
TwoWheelerHandoverState (returned by get_handover_state)
booking_ref: string, REQUIRED
status: STRICT ENUM, REQUIRED
status_updated_iso: ISO_DATETIME, REQUIRED
status_history: array, REQUIRED, ≥1
handover_window:
pickup_window_open_iso: ISO_DATETIME, REQUIRED
pickup_window_close_iso: ISO_DATETIME, REQUIRED
return_window_open_iso: ISO_DATETIME, REQUIRED
return_window_close_iso: ISO_DATETIME, REQUIRED
vehicle:
vehicle_kind: STRICT ENUM, REQUIRED
display_label: string, REQUIRED
color: string, REQUIRED
plate_masked: string, REQUIRED
current_lat: float, REQUIRED
current_lng: float, REQUIRED
current_state_code: string, REQUIRED
current_speed_kmh: float, REQUIRED, ≥0
current_fuel_level_pct: int, REQUIRED, 0-100
odometer_reading_km: int, REQUIRED, ≥0
geofence_breach_active: boolean, REQUIRED
speed_limit_breach_active: boolean, REQUIRED
helmet_strap_breach_active: boolean, REQUIRED # rider unhelmeted
usage_so_far:
km_driven: float, REQUIRED, ≥0
hours_elapsed: int, REQUIRED, ≥0
fuel_consumed_litres: float, REQUIRED, ≥0
current_overage_charge_inr: INR_INTEGER, REQUIRED, ≥0
incidents:
incidents_reported: int, REQUIRED, ≥0
open_incidents: array, REQUIRED, may be empty
dl_verification:
required: boolean, REQUIRED
verified_iso: ISO_DATETIME, REQUIRED
verification_method: STRICT ENUM, REQUIRED
support_phone: string, REQUIRED
support_email: string, REQUIRED
Forbidden fields
paid_placement_score | sponsored_rank | promotion_priority |
artificial_demand_text | fake_recent_booking_text |
auto_inflate_user_age_min | partner_paid_for_top_listing |
hidden_deposit_inr | undocumented_helmet_loss_inr |
fake_isi_certified | uncertified_helmet_charged_as_certified
5. CONTROLLED VOCABULARIES
vehicle_kind
scooter | geared_bike | premium_bike | adventure_bike | cruiser_bike |
sport_bike | electric_scooter | electric_bike | electric_moped
vehicle_class
economy | comfort | premium | sport | adventure | cruiser
transmission (implicit, no input field needed)
Most scooters: CVT-automatic. Geared bikes: manual gearbox. Auto-classified by partner per vehicle.
pickup_location.hub_kind and drop_location.hub_kind
branded_hub | partner_dealership | metro_station_zone |
mall_parking | doorstep_delivery
rental_kind
round_trip | one_way
fare.fuel_policy
full_to_full | empty_to_empty | as_is | included
vehicle_meta.fuel_kind
petrol | ev_full | hybrid | bs6_petrol
vehicle_meta.emission_norm
bs3 | bs4 | bs6 | ev | unknown_legacy
vehicle_meta.permit_kind
self_drive_permit | private
vehicle_meta.vehicle_class_certification
private | self_drive_yellow_plate
vehicle_meta.geofence_kind
none | city_only | state_only | multi_state_specified | nationwide
gear_kit.rider_helmet_size_options[]
xs | s | m | l | xl | xxl
deposit.hold_kind
card_block | bank_transfer | wallet_hold | none
rider_qualification_for_user.qualification_failure_reason
none | user_age_below_minimum | license_held_too_short |
license_2w_endorsement_missing | license_2w_geared_missing |
license_expired | foreign_license_not_accepted | prior_incident_block
TwoWheelerHandoverState.status
booked_pending_pickup | dl_verification_required | dl_verified |
ready_for_pickup | helmet_handed_over | picked_up | in_use |
return_pending | returned_pending_inspection | inspection_complete |
completed | cancelled_by_user | cancelled_by_partner | failed |
incident_open | extended
dl_verification.verification_method
digilocker | parivahan | manual_kyc | none
incidents[].incident_kind
breakdown | accident | flat_tyre | dead_battery | fuel_empty |
mechanical_warning | exterior_damage_observed | theft_attempt |
geofence_breach | helmet_strap_breach | speed_limit_breach | other
cancel_two_wheeler.reason
user_changed_mind | wrong_vehicle | wrong_pickup_address |
vehicle_unavailable | safety_concern | weather_cancellation |
no_longer_needed | found_alternative | emergency
context.trip_intent.purpose
commute_to_office | commute_to_home | leisure | college |
errand | sightseeing | food_pickup | other
6. TTBS DIMENSIONS
Per-domain weights (locked; 2W mirrors self-drive: safety up)
mobility (two_wheeler_rental): { time: 0.20, taste: 0.20, budget: 0.30, safety: 0.30 }
TIME
SIGNALS USED:
- availability.vehicle_ready_at_iso ≤ pickup_iso HARD FILTER
- availability.doorstep_delivery_available weight 0.20
- availability.alternate_pickup_hubs count weight 0.10
- cancellation.refund_processing_days (lower=better) weight 0.10
USER BAND HANDLING:
- "right now" → drop options where vehicle_ready_at_iso > now+15min
TASTE
SIGNALS USED:
- vehicle.year_of_manufacture (newer = better) weight 0.25
- vehicle.make/model affinity (DNA-personalized) weight 0.25
- vehicle_amenities match w/ user prefs weight 0.20
- gear_kit.jacket_with_armor (if requested) weight 0.10
- vehicle_amenities.bluetooth_console weight 0.10
- vehicle_amenities.led_headlight weight 0.10
HARD FILTERS:
- fuel_kinds_acceptable doesn't include vehicle_meta.fuel_kind → drop
- engine_cc_max < vehicle.engine_cc → drop (user wanted ≤125, got 350)
- min_pillion_capacity > vehicle.pillion_capacity → drop
BUDGET
SIGNALS USED:
- fare.total_inr vs band:
ok → scooter / electric_scooter (basic)
good → geared_bike (mid) / premium scooter
great → premium_bike / cruiser_bike / sport_bike
- fare.is_upfront_fare=true weight 0.15
- fare.included_km vs trip_intent.expected_distance_km weight 0.20
- fare.late_return_per_hour_inr (lower) weight 0.10
- deposit.amount_inr (lower) weight 0.15
- bundled gear (helmet+raincoat at 0 cost) weight 0.10
HARD FILTERS:
- fare.total_inr > preferences.budget_max_inr → drop
SAFETY
SIGNALS USED:
- vehicle_meta.comprehensive_insurance HARD FILTER
- vehicle_meta.permit_kind = self_drive_permit HARD FILTER
- rider_qualification_for_user.user_meets_qualification HARD FILTER
- gear_kit.rider_helmet_provided AND rider_helmet_isi_certified HARD FILTER
- gear_kit.pillion_helmet_provided AND pillion_helmet_isi_certified (if requested) HARD FILTER
- gear_kit.knee_guards_provided weight 0.10
- gear_kit.gloves_provided weight 0.10
- vehicle_meta.helmet_strap_sensor weight 0.20
- vehicle_meta.abs weight 0.15
- vehicle_meta.cbs (if no abs) weight 0.10
- vehicle_meta.speed_limit_governed weight 0.10
- vehicle_meta.fitness_certificate_valid_until_iso > scheduled_return_iso HARD FILTER
- partner_safety_features.helmet_verification_at_pickup weight 0.15
- partner_safety_features.roadside_assistance_24x7 weight 0.15
- partner_safety_features.emergency_swap_vehicle weight 0.10
- vehicle_photos.pre_handover_photos_required=true HARD FILTER
- is_late_night_pickup → safety weight scales 1.5x
HARD FILTERS:
- geared_endorsement_required AND license_endorsement_2w_with_gear=false → drop
- is_overnight=true AND vehicle_kind in [scooter, electric_scooter] → drop (city scooters not for overnight long-distance)
- involves_highway=true AND vehicle.engine_cc < 100 → drop
Hidden ranking factor
information_completeness_score weight 0.10.
7. COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
X-TOMO-Timestamp: <ms>
X-TOMO-Signature: sha256=<hex>
{
"intent": "mobility.book_two_wheeler_rental",
"intent_version": "v1.0.0",
"external_id": "BOUNCE-2W-XYZ",
"amount_inr": 320,
"closed_at": "2026-05-10T18:14:00+05:30",
"request_id": "req_2w_5h7m_...",
"status": "completed",
"booking_ref": "BOUNCE-2W-XYZ",
"picked_up_at": "2026-05-10T09:08:00+05:30",
"returned_at": "2026-05-10T17:55:00+05:30",
"km_driven": 38.4,
"billed_hours_actual": 9,
"fuel_top_up_charge_inr": 40,
"damage_charge_inr": 0,
"helmet_loss_charge_inr": 0,
"late_return_charge_inr": 0,
"deposit_refunded_inr": 1000,
"incidents_reported": 0,
"currency": "INR",
"fare_breakdown_total_inr": 320,
"ratings_pending": true,
"notes": ""
}
Status enum: completed | cancelled_by_user | cancelled_by_partner | failed | partial_completion_user_returned_early | extended_and_completed | terminated_with_damage_claim
8. WIDGET
WIDGET TYPE: two_wheeler_options
SOURCE: src/widgets/types.ts
TYPE NAME: TwoWheelerOptionsPayload
RENDERED IN: components/widgets/TwoWheelerOptionsWidget.tsx
Default: 3 stacked rows showing make+model+year, engine_cc badge or EV-range, fuel kind, fare with helmet/raincoat line callouts, included_km, hub address. Tap row → confirmation card with full fare breakdown + gear kit visual + DL upload widget → "Book". Then TwoWheelerHandoverCard with handover window + helmet size selection + condition photo gallery.
9. CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
get_two_wheeler_inventory |
60s | inventory turns over slowly |
get_handover_state |
0s | always live during rental |
book_two_wheeler |
0s | |
cancel_two_wheeler |
0s | |
extend_two_wheeler |
0s | |
report_damage_or_incident |
0s | |
complete_return |
0s | |
| Failure responses | 0s |
10. ERROR CODES
| Code | HTTP | Meaning | TOMO behavior |
|---|---|---|---|
NO_INVENTORY |
503 | no vehicle matches | retry or fall back |
OUT_OF_SERVICE_AREA |
400 | pickup outside coverage | surface |
OPTION_EXPIRED |
410 | option_token invalid | re-quote |
USER_NOT_QUALIFIED |
403 | age/license/endorsement fails | surface qualification_failure_reason |
DL_VERIFICATION_FAILED |
401 | DL image rejected | surface, retry |
DL_2W_ENDORSEMENT_MISSING |
403 | user has only LMV; needs 2W | surface |
DEPOSIT_DECLINED |
402 | card block / hold failed | surface |
BOOKING_NOT_FOUND |
404 | booking_ref doesn't exist | surface |
ALREADY_CANCELLED |
409 | duplicate cancel | idempotent return |
EXTENSION_BLOCKED |
409 | reserved for next user | surface alternate |
GEOFENCE_BREACH |
403 | vehicle outside allowed states | surface |
HELMET_NOT_RETURNED |
400 | return without helmets | surface helmet_loss_charge |
INCIDENT_OPEN |
409 | active incident blocks state change | surface |
RETURN_LATE_BEYOND_GRACE |
400 | late return triggers extra | surface fare delta |
11. SANDBOX → PRODUCTION CHECKLIST
[ ] All §2 inputs validated, request_id echoed
[ ] get_two_wheeler_inventory returns ≥3 options
[ ] All §4 required fields populated with REAL data
[ ] vehicle_meta truthful + verifiable on demand
[ ] insurance_company verifiable (IRDAI registered)
[ ] permit_kind = self_drive_permit verified per state RTO
[ ] geofence_states_allowed enforced server-side via telematics
[ ] book_two_wheeler returns booking_ref + handover window within SLA
[ ] DL verification flow works via DigiLocker / Parivahan
[ ] license_endorsement_2w gate enforced server-side
[ ] license_endorsement_2w_with_gear gate enforced for geared bikes
[ ] deposit hold tested with sandbox card
[ ] pre_handover_photos uploaded for every booking (≥4 angles)
[ ] gear_kit dispatched matching ordered config (helmet/raincoat/etc.)
[ ] rider_helmet_isi_certified verifiable via BIS standard
[ ] helmet_verification_at_pickup procedure shown to TOMO ops
[ ] helmet_strap_sensor data flows to telematics (sample data)
[ ] cancel respects free_cancel_until_iso
[ ] extend recomputes fare correctly
[ ] complete_return computes damage + late + helmet-loss charges deterministically
[ ] CPC webhook arrives within 60s of return completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] SOS button tested with TOMO ops monitoring
[ ] Roadside assistance dispatched within SLA in dry-run
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] Self-drive permit certificate uploaded for every operating state
12. ANTI-FABRICATION RULES
RULE 1 — No paid placement signals.
RULE 2 — No fake ISI certification.
rider_helmet_isi_certified=true requires BIS-certified helmet (IS 4151).
Charging for ISI helmet but providing non-ISI = breach + safety violation.
RULE 3 — No hidden deposit.
deposit.amount_inr declared up-front. Post-booking ask = breach.
RULE 4 — No undocumented helmet loss charge.
helmet_loss_charge_inr disclosed at booking. Unilateral upgrade at return = breach.
RULE 5 — No fake helmet-strap telemetry.
helmet_strap_sensor=true must be backed by actual sensor data. Charging
helmet-strap-breach without sensor evidence = breach.
RULE 6 — No fake geofence enforcement.
geofence_states_allowed must be enforced via telematics. Charging
geofence-breach without telematics evidence = breach.
RULE 7 — Damage claims must be photo-backed.
damage_charge_inr > 0 requires return_photos showing damage NOT in
pre_handover_photos. Charging without photo evidence = breach.
RULE 8 — Late return grace honored.
Stated grace (e.g., 15 min) cannot be reduced retroactively.
RULE 9 — Fuel policy honored.
full_to_full means user returns at same fuel level. Charging fuel_top_up
beyond actual delta = breach.
RULE 10 — No commission-based response shaping.
RULE 11 — Vehicle swap requires user consent.
RULE 12 — Speed-limit-governed claim must be testable.
speed_limit_governed=true must actually electronically limit. Throttle-soft
governance that user can bypass = breach.
RULE 13 — Helmet verification at pickup is non-negotiable.
Partner staff MUST verify user fits helmet correctly before handover.
Skipping for "speed" = safety breach.
VERSION HISTORY
v1.0.0 — 2026-05-10 — Initial spec