mobility.book_intercity_ride — Full Intent Specification
INTENT NAMESPACE: mobility
INTENT NAME: book_intercity_ride
FULL ID: mobility.book_intercity_ride
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-10
TTBS WEIGHTS: time 0.30 · taste 0.10 · budget 0.30 · safety 0.30
Intercity rides differ from intracity in four locked ways: (a) always scheduled, never ASAP; (b) multi-toll FASTag arithmetic is load-bearing, not nice-to-have; (c) driver allowance + night halt + state-border charges expand the fare breakdown; (d) safety weight rises (highway, longer exposure, fatigue risk).
1. NATURAL LANGUAGE COVERAGE
Classifies IN
- "Hyderabad to Bangalore cab tomorrow morning"
- "book a cab to Vijayawada on Friday"
- "intercity ride Mumbai to Pune Saturday 6am"
- "one-way taxi to Tirupati Sunday"
- "Hyderabad to Warangal Innova for 4 people"
- "round trip cab to Goa next weekend"
- "Hyderabad to Chennai outstation tomorrow"
- "drop me to Bengaluru by Sunday evening"
- "we're 6 people, intercity Tempo Traveller to Coorg"
Classifies OUT — borderline NO
- "ride to airport" →
mobility.book_intracity_ride(ormobility.book_airport_transfer) - "self-drive Innova for the weekend Hyderabad to Goa" →
mobility.book_self_drive - "Goa 4N5D package with cab" →
mobility.book_outstation_package - "chauffeur for full day in Bangalore" →
mobility.book_chauffeur_hourly - "auto to MG Road" →
mobility.book_intracity_ride - "I want to drive to Goa myself" → no intent (informational)
MULTI-INTENT TRIGGERS
- "Hyderabad to Bangalore cab Friday morning, also book hotel near MG Road" →
mobility.book_intercity_ride+travel.book_hotel - "intercity to Tirupati and dinner reservation on the way at Tirupati Bhojanam" →
mobility.book_intercity_ride+food.book_dine_in - "cab to Vijayawada round trip and recharge FASTag" →
mobility.book_intercity_ride+pay.fastag_topup
2. INPUT — TOMO → PROVIDER
{
"intent": "mobility.book_intercity_ride",
"intent_version": "v1.0.0",
"request_id": "req_intc_8h2k_2026-05-10T06:14:00Z",
"user_session_id": "anon_user_token_or_uid",
"pickup": {
"lat": 17.4435,
"lng": 78.3772,
"address": "HITEC City Main Road, Madhapur",
"neighborhood": "Madhapur",
"city": "Hyderabad",
"pincode": "500081",
"state_code": "TS",
"country_code": "IN",
"place_kind": "office",
"instructions": "Pickup gate B"
},
"drop": {
"lat": 12.9716,
"lng": 77.5946,
"address": "MG Road Metro, Bangalore",
"neighborhood": "MG Road",
"city": "Bangalore",
"pincode": "560001",
"state_code": "KA",
"country_code": "IN",
"place_kind": "hotel",
"instructions": "Lobby of Taj MG Road"
},
"intermediate_stops": [
{
"lat": 16.5062,
"lng": 80.6480,
"address": "Vijayawada food court NH-65",
"city": "Vijayawada",
"stop_kind": "food_break",
"expected_minutes": 30
}
],
"trip_kind": "one_way",
"scheduled_pickup_iso": "2026-05-11T06:00:00+05:30",
"scheduled_return_iso": null,
"expected_return_after_days": 0,
"party": {
"passenger_count": 4,
"luggage_pieces": 6,
"luggage_size": "checkin",
"minor_count": 1,
"senior_count": 0
},
"preferences": {
"vehicle_kinds_acceptable": ["sedan_intercity", "suv_intercity", "tempo_traveller"],
"budget_band": "good",
"budget_max_inr": 14500,
"ac_required": true,
"female_driver_required": false,
"ev_only": false,
"wheelchair_accessible_required": false,
"child_seat_required": true,
"max_seat_capacity_min": 4,
"driver_must_speak_locales": ["en-IN", "te-IN", "kn-IN"],
"no_pool": true
},
"route_context": {
"estimated_distance_km": 570.0,
"estimated_duration_min": 540,
"involves_toll": true,
"toll_count": 7,
"states_crossed": ["TS", "AP", "KA"],
"state_border_count": 2,
"involves_highway": true,
"primary_highway_codes": ["NH-65", "NH-44"],
"weather_celsius": 29,
"rain_probability_pct": 30,
"current_aqi": 135,
"is_overnight": false,
"is_late_night_departure": false,
"is_late_night_arrival": false,
"is_surge_window": false
},
"context": {
"user_locale": "en-IN",
"user_currency_pref": "INR",
"trip_purpose": "leisure",
"trust_signals": {
"is_repeat_customer": true,
"prior_intercity_rides_with_partner": 4,
"user_account_age_days": 312,
"fastag_present": true,
"fastag_balance_inr": 1840
}
}
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, equals "mobility.book_intercity_ride" |
|
pickup.state_code |
string | REQUIRED | mandatory for intercity (different from intracity) |
drop.state_code |
string | REQUIRED | |
intermediate_stops |
array | REQUIRED, may be empty | each stop has full address + stop_kind |
intermediate_stops[].stop_kind |
enum | REQUIRED, see §5 | |
trip_kind |
enum | REQUIRED, STRICT one_way | round_trip |
|
scheduled_pickup_iso |
ISO_DATETIME | REQUIRED | no ASAP for intercity |
scheduled_return_iso |
ISO_DATETIME or null | REQUIRED, null only if trip_kind=one_way |
|
expected_return_after_days |
int | REQUIRED, ≥0 | drives night halt charge math |
party.minor_count |
int | REQUIRED, ≥0 | child seat + safety weight |
party.senior_count |
int | REQUIRED, ≥0 | comfort + medical-assist signals |
route_context.states_crossed |
array |
REQUIRED, ≥1 | ISO 3166-2:IN state codes |
route_context.state_border_count |
int | REQUIRED, ≥0 | drives state-border charge |
route_context.primary_highway_codes |
array |
REQUIRED, may be empty | for permit + safety routing |
route_context.is_overnight |
bool | REQUIRED | true if pickup→drop crosses 23:00–05:00 |
route_context.is_late_night_departure |
bool | REQUIRED | pickup_local_time in [22:30, 05:30) |
route_context.is_late_night_arrival |
bool | REQUIRED | arrival_local_time in [22:30, 05:30) |
context.trust_signals.fastag_balance_inr |
INR_INTEGER | REQUIRED, ≥0 | TOMO computes sufficiency vs estimated_toll_total_inr |
Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.
3. PROVIDER TOOLS
Tool 1: get_intercity_estimates
PURPOSE: return intercity ride options across vehicle kinds
INPUT: §2 request body
OUTPUT: { options: IntercityRideOption[], result_token, expires_at }
SLA: p50 < 600ms, p95 < 1500ms
RATE LIMIT: ≤ 1/sec per user
Tool 2: book_intercity_ride
PURPOSE: commit a ride
INPUT: { ride_option_id, payment_token, request_id, idempotency_key, user_phone, otp_required }
OUTPUT: { ride_ref, status, driver, vehicle, fare_quote, otp_for_driver, allowance_breakdown }
SLA: p95 < 5000ms
IDEMPOTENCY: REQUIRED on idempotency_key
Tool 3: track_intercity_ride
PURPOSE: live ride state + driver location + leg progress
INPUT: { ride_ref, request_id }
OUTPUT: IntercityRideTrack (§4)
SLA: p95 < 500ms
RATE LIMIT: ≤ 1 every 10s
Tool 4: cancel_intercity_ride
PURPOSE: cancel
INPUT: { ride_ref, reason, request_id }
OUTPUT: { status, cancellation_charge_inr, refund_amount_inr, cancellation_window_kind }
SLA: p95 < 2000ms
Tool 5: update_intercity_stops
PURPOSE: add or modify intermediate stops mid-trip
INPUT: { ride_ref, new_stops[], removed_stop_indices[], request_id }
OUTPUT: { revised_fare_inr, revised_duration_min, status }
SLA: p95 < 1500ms
Tool 6: rate_intercity_ride
PURPOSE: post-ride rating
INPUT: { ride_ref, rating_5star, comment, tip_inr, request_id }
OUTPUT: { acknowledged: true }
SLA: p95 < 800ms
Tool 7: share_trip_status
PURPOSE: tokenized URL for live trip sharing
INPUT: { ride_ref, recipient_phone_optional, request_id }
OUTPUT: { share_url, expires_at }
SLA: p95 < 500ms
All seven REQUIRED.
4. RESPONSE SHAPE
IntercityRideOption (returned by get_intercity_estimates)
id: string, REQUIRED
ride_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 # "Innova Crysta Intercity"
seat_capacity: int, REQUIRED, ≥1
luggage_capacity: STRICT ENUM, REQUIRED
eta:
pickup_minutes: int, REQUIRED # driver-to-pickup window (large for intercity)
trip_minutes: int, REQUIRED # full intercity duration
total_minutes: int, REQUIRED
arrival_eta_iso: ISO_DATETIME, REQUIRED # pickup_iso + total_minutes
driver_pre_dispatch_minutes: int, REQUIRED # how early driver is dispatched
fare:
total_inr: INR_INTEGER, REQUIRED
base_inr: INR_INTEGER, REQUIRED
per_km_inr: float, REQUIRED
total_km_charged: float, REQUIRED # often inflated for return-empty
driver_allowance_inr: INR_INTEGER, REQUIRED # daily DA
night_halt_charge_inr: INR_INTEGER, REQUIRED # if overnight
night_halt_count: int, REQUIRED, ≥0
toll_inr: INR_INTEGER, REQUIRED
toll_count: int, REQUIRED, ≥0
state_border_charge_inr: INR_INTEGER, REQUIRED # 0 if same-state
state_border_count: int, REQUIRED, ≥0
highway_charge_inr: INR_INTEGER, REQUIRED # 0 if not applicable
ac_charge_inr: INR_INTEGER, REQUIRED # 0 if AC default
late_night_charge_inr: INR_INTEGER, REQUIRED # 0 if not late
parking_charge_inr: INR_INTEGER, REQUIRED
platform_fee_inr: INR_INTEGER, REQUIRED
gst_inr: INR_INTEGER, REQUIRED
rider_tip_optional_inr: INR_INTEGER, REQUIRED # default 0
fare_breakdown_text: string, REQUIRED
is_upfront_fare: boolean, REQUIRED
fare_locked_until_iso: ISO_DATETIME, REQUIRED
return_trip_empty_pricing: boolean, REQUIRED # true if user pays for empty return
per_km_overage_inr: float, REQUIRED # rate beyond included_km
included_km: int, REQUIRED # cap before overage starts
vehicle_amenities:
ac: boolean, REQUIRED
music_on_demand: boolean, REQUIRED
charging_port: boolean, REQUIRED
wifi_in_cab: boolean, REQUIRED
bottled_water: boolean, REQUIRED
newspaper: boolean, REQUIRED
pet_friendly: boolean, REQUIRED
child_seat_available: boolean, REQUIRED
child_seat_kind: STRICT ENUM, REQUIRED
wheelchair_accessible: boolean, REQUIRED
recliner_seats: boolean, REQUIRED
panoramic_roof: boolean, REQUIRED
fridge_in_cabin: boolean, REQUIRED # luxury intercity only
oxygen_supply_for_emergency: boolean, REQUIRED
vehicle_meta:
age_years: int, REQUIRED
fuel_kind: STRICT ENUM, REQUIRED
fuel_efficiency_kmpl: float, REQUIRED
ev_battery_charge_pct: int, REQUIRED, 0-100
ev_range_km_remaining: int, REQUIRED # 0 if not EV
emission_norm: STRICT ENUM, REQUIRED
registration_state_code: string, REQUIRED
vehicle_class_certification: STRICT ENUM, REQUIRED
comprehensive_insurance: boolean, REQUIRED
insurance_valid_until_iso: ISO_DATE, REQUIRED
fitness_certificate_valid_until_iso: ISO_DATE, REQUIRED
puc_valid_until_iso: ISO_DATE, REQUIRED
permit_kind: STRICT ENUM, REQUIRED # tourist | contract_carriage required for intercity
all_india_tourist_permit: boolean, REQUIRED
permit_states_covered: array<string>, REQUIRED, ≥1
commercial_aggregator_permit_number: string, REQUIRED
vehicle_color: string, REQUIRED
last_serviced_iso: ISO_DATE, REQUIRED
odometer_reading_km: int, REQUIRED, ≥0
driver_meta:
driver_id: string, REQUIRED
display_name: string, REQUIRED
photo_url: URL, REQUIRED
rating_avg: float, REQUIRED, 0-5
rides_completed_total: int, REQUIRED, ≥0
intercity_rides_completed: int, REQUIRED, ≥0
partner_account_age_days: int, REQUIRED, ≥0
languages_spoken: array<RFC_3066_LOCALE>, REQUIRED, ≥1
female_driver: boolean, REQUIRED
age_band: STRICT ENUM, REQUIRED
experience_years_driving: int, REQUIRED, ≥0
highway_experience_years: int, REQUIRED, ≥0
states_familiar_with: array<string>, REQUIRED, ≥1
defensive_driving_certified: boolean, REQUIRED
driver_kyc:
dl_verified: boolean, REQUIRED
dl_number_masked: string, REQUIRED
dl_valid_until_iso: ISO_DATE, REQUIRED
dl_class_includes_lmv: boolean, REQUIRED
rc_verified: boolean, REQUIRED
aadhaar_verified: boolean, REQUIRED
pan_verified: boolean, REQUIRED
background_check_passed: boolean, REQUIRED
background_check_iso: ISO_DATETIME, REQUIRED
badge_id_displayed: boolean, REQUIRED
fatigue_compliance_certified: boolean, REQUIRED # MV Act drive-hours cap
safety_features:
sos_button_in_app: boolean, REQUIRED
trip_share_supported: boolean, REQUIRED
in_app_chat_supported: boolean, REQUIRED
in_app_call_supported: boolean, REQUIRED
emergency_contact_alerts: boolean, REQUIRED
cctv_in_cab: boolean, REQUIRED
panic_alert_to_local_police: boolean, REQUIRED
driver_drowsiness_detection: boolean, REQUIRED
speed_limit_governing: boolean, REQUIRED
highway_assist_telematics: boolean, REQUIRED
spare_tyre_present: boolean, REQUIRED
first_aid_kit_present: boolean, REQUIRED
fire_extinguisher_present: boolean, REQUIRED
reflective_triangle_present: boolean, REQUIRED
route_quality:
estimated_distance_km: float, REQUIRED
estimated_duration_min: int, REQUIRED
highway_kms: float, REQUIRED
inner_road_kms: float, REQUIRED
states_crossed_count: int, REQUIRED, ≥1
primary_highway_codes: array<string>, REQUIRED, may be empty
toll_passes: array, REQUIRED, may be empty
- toll_name: string, REQUIRED
toll_amount_inr: INR_INTEGER, REQUIRED
fastag_supported: boolean, REQUIRED
cash_accepted: boolean, REQUIRED
state_code: string, REQUIRED
cancellation:
free_cancel_until_iso: ISO_DATETIME, REQUIRED # absolute time, not relative window
cancel_charge_after_grace_inr: INR_INTEGER, REQUIRED
cancel_charge_within_24h_inr: INR_INTEGER, REQUIRED
cancel_charge_within_2h_inr: INR_INTEGER, REQUIRED
no_show_charge_inr: INR_INTEGER, REQUIRED
driver_cancel_compensation_inr: INR_INTEGER, REQUIRED
refund_processing_days: int, REQUIRED, ≥0
fastag_check:
toll_count_on_route: int, REQUIRED, ≥0
fastag_required: boolean, REQUIRED
estimated_toll_total_inr: INR_INTEGER, REQUIRED
user_fastag_balance_sufficient: boolean, REQUIRED
fastag_topup_recommended_inr: INR_INTEGER, REQUIRED # 0 if not required
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
in_app_chat_supported: boolean, REQUIRED
partner_intercity_volume_30d: int, REQUIRED, ≥0
IntercityRideTrack (returned by track_intercity_ride)
ride_ref: string, REQUIRED
status: STRICT ENUM, REQUIRED # see §5
status_updated_iso: ISO_DATETIME, REQUIRED
status_history: array, REQUIRED, ≥1
- status: STRICT ENUM, REQUIRED
iso: ISO_DATETIME, REQUIRED
leg_progress:
current_leg_index: int, REQUIRED, ≥0 # 0 = pickup→stop1, etc.
total_legs: int, REQUIRED, ≥1
current_leg_distance_remaining_km: float, REQUIRED
next_stop_kind: STRICT ENUM, REQUIRED # food_break | refuel | washroom | drop | none
driver:
driver_id: string, REQUIRED
display_name: string, REQUIRED
phone_masked: string, REQUIRED
photo_url: URL, REQUIRED
rating_avg: float, REQUIRED, 0-5
in_app_chat_supported: boolean, REQUIRED
in_app_call_supported: boolean, REQUIRED
cumulative_drive_minutes_today: int, REQUIRED, ≥0 # fatigue audit
vehicle:
vehicle_kind: STRICT ENUM, REQUIRED
display_label: string, REQUIRED
color: string, REQUIRED
plate_masked: string, REQUIRED
location:
current_lat: float, REQUIRED
current_lng: float, REQUIRED
current_state_code: string, REQUIRED
heading_degrees: float, REQUIRED, 0-360
speed_kmh: float, REQUIRED, ≥0
location_updated_iso: ISO_DATETIME, REQUIRED
status: STRICT ENUM, REQUIRED
eta:
to_next_stop_minutes: int, REQUIRED
to_drop_minutes: int, REQUIRED
revised_fare_inr: INR_INTEGER, REQUIRED
detour_minutes: int, REQUIRED
ride_safety:
on_route: boolean, REQUIRED
unusual_stop_detected: boolean, REQUIRED
unusual_speed_detected: boolean, REQUIRED
driver_fatigue_warning_active: boolean, REQUIRED
trip_share_active: boolean, REQUIRED
trip_share_url: URL, REQUIRED
fastag:
next_toll_distance_km: float, REQUIRED # 9999 if none
next_toll_amount_inr: INR_INTEGER, REQUIRED
user_fastag_balance_sufficient_for_remaining_tolls: boolean, 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_driver_rating | partner_paid_for_top_listing |
fake_intercity_volume_30d | inflated_highway_experience_years
5. CONTROLLED VOCABULARIES
vehicle_kind
sedan_intercity | suv_intercity | premium_sedan_intercity |
premium_suv_intercity | tempo_traveller | mini_bus |
ev_sedan_intercity | ev_suv_intercity | luxury_sedan_intercity | luxury_suv_intercity
vehicle_class
economy | comfort | premium | luxury | xl | xl_premium
IntercityRideOption.luggage_capacity
small | medium | large | xl | xxl
pickup.place_kind and drop.place_kind
home | office | airport | railway | metro_station | bus_terminal |
hotel | restaurant | mall | hospital | clinic | school | college |
event_venue | religious_place | landmark | other
intermediate_stops[].stop_kind
food_break | washroom | refuel | charge_ev | religious_visit |
sightseeing | medical | luggage_pickup | passenger_pickup | other
trip_kind
one_way | round_trip
party.luggage_size
none | handbag | backpack | cabin | checkin | oversized
route_context.is_overnight
boolean. Definition: any portion of trip falls between 23:00 and 05:00 local.
IntercityRideOption.vehicle_meta.fuel_kind
petrol | diesel | cng | lpg | ev_full | hybrid | bs6_petrol | bs6_diesel
IntercityRideOption.vehicle_meta.emission_norm
bs3 | bs4 | bs6 | ev | unknown_legacy
IntercityRideOption.vehicle_meta.permit_kind
tourist | contract_carriage | aggregator_permit | all_india_tourist
Intercity REQUIRES one of tourist | all_india_tourist | contract_carriage. Aggregator-only permits are NOT valid for cross-state trips.
IntercityRideOption.vehicle_meta.vehicle_class_certification
commercial_yellow_plate | tourist | tempo_traveller | luxury_charter
vehicle_amenities.child_seat_kind
none | infant | toddler | booster | universal
driver_meta.age_band
21-30 | 31-40 | 41-55 | 56+
Note: minimum 21 for intercity (commercial highway).
IntercityRideTrack.status
scheduled | driver_assigned | driver_dispatched | driver_arriving |
arrived_at_pickup | otp_required | trip_started | en_route_leg_1 |
at_intermediate_stop | en_route_leg_n | nearby_drop |
completed | cancelled_by_user | cancelled_by_driver |
delayed_by_driver | delayed_by_route | failed
IntercityRideTrack.location.status
heading_to_pickup | at_pickup | trip_in_progress | at_food_stop |
at_refuel_stop | at_charge_stop | crossing_state_border |
nearby_drop | reached_drop
leg_progress.next_stop_kind
food_break | refuel | washroom | charge_ev | religious_visit |
sightseeing | medical | drop | none
cancel_intercity_ride.reason
user_changed_mind | wrong_vehicle | wrong_address | driver_too_far |
driver_unresponsive | safety_concern | weather_cancellation |
no_longer_needed | found_alternative | emergency
context.trip_purpose
commute_to_work | commute_to_home | leisure | family_visit |
medical_visit | religious_pilgrimage | wedding_event | business_trip |
funeral | emergency | other
6. TTBS DIMENSIONS
Per-domain weights (locked; intercity override on safety)
mobility (intercity): { time: 0.30, taste: 0.10, budget: 0.30, safety: 0.30 }
Safety up from 0.20 (intracity) to 0.30 — highway exposure, fatigue risk, longer trip.
TIME
SIGNALS USED:
- eta.pickup_minutes weight 0.20
- eta.driver_pre_dispatch_minutes (lower=better) weight 0.10
- route_quality.estimated_duration_min weight 0.40
- route_quality.highway_kms / total_km weight 0.20 (more highway = faster)
- cancellation.refund_processing_days (low=trust) weight 0.10
USER BAND HANDLING:
- "by 6pm Sunday" hard arrival → arrival_eta_iso ≤ deadline → HARD FILTER
- "earliest possible" → upweight pickup_minutes 0.40
TASTE
SIGNALS USED:
- driver_meta.rating_avg weight 0.30
- vehicle_meta.age_years (newer = better) weight 0.15
- vehicle_amenities match w/ user prefs weight 0.30
- driver languages match user_locale + states weight 0.15
- vehicle_amenities.recliner_seats (long trip) weight 0.10
HARD FILTER:
- ac_required + ac=false → drop
BUDGET
SIGNALS USED:
- fare.total_inr vs band:
ok → sedan_intercity / EV economy
good → suv_intercity / sedan_intercity_premium
great → luxury_sedan_intercity / luxury_suv_intercity
- fare.return_trip_empty_pricing=false (better) weight 0.20
- fare.is_upfront_fare=true (locked = better) weight 0.20
- fastag_topup_recommended_inr (lower or zero) weight 0.10
HARD FILTERS:
- fare.total_inr > preferences.budget_max_inr → drop
USER BAND HANDLING:
- emergency trip_purpose → budget weight 0.50 of stated → safety upweighted
- leisure trip → budget weight unchanged
SAFETY
SIGNALS USED:
- driver_kyc.background_check_passed HARD FILTER
- driver_kyc.dl_class_includes_lmv HARD FILTER
- driver_kyc.fatigue_compliance_certified HARD FILTER
- vehicle_meta.comprehensive_insurance HARD FILTER
- vehicle_meta.permit_kind in (tourist|all_india_tourist|contract_carriage) HARD FILTER
- vehicle_meta.permit_states_covered ⊇ states_crossed HARD FILTER
- safety_features.sos_button_in_app weight 0.10
- safety_features.driver_drowsiness_detection weight 0.15
- safety_features.highway_assist_telematics weight 0.15
- safety_features.first_aid_kit_present weight 0.05
- safety_features.fire_extinguisher_present weight 0.05
- safety_features.reflective_triangle_present weight 0.05
- driver_meta.intercity_rides_completed (≥20) weight 0.15
- driver_meta.highway_experience_years (≥3) weight 0.10
- driver_meta.defensive_driving_certified weight 0.10
- driver_meta.female_driver
(boosted if female_driver_required) weight 0.10
- is_overnight → safety weight scales 1.6x
- is_late_night_arrival → trip_share enforced
HARD FILTERS:
- female_driver_required → drop male drivers
- child_seat_required AND minor_count > 0 → drop without seat
- ev_only → drop non-EV
- states_crossed not covered by permit → drop
Hidden ranking factor
information_completeness_score weight 0.10.
FASTag check
If route_context.involves_toll AND user_fastag_balance_sufficient = false, TOMO surfaces a top-up CTA before booking. For intercity, also surface FASTag balance vs estimated_toll_total_inr at the option-card level (not just confirmation).
7. COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
X-TOMO-Timestamp: <ms>
X-TOMO-Signature: sha256=<hex>
{
"intent": "mobility.book_intercity_ride",
"intent_version": "v1.0.0",
"external_id": "OLA-INTC-XYZ",
"amount_inr": 13800,
"closed_at": "2026-05-11T15:34:00+05:30",
"request_id": "req_intc_8h2k_...",
"status": "completed",
"ride_ref": "OLA-INTC-XYZ",
"started_at": "2026-05-11T06:08:00+05:30",
"completed_at": "2026-05-11T15:34:00+05:30",
"distance_traveled_km": 583.2,
"duration_minutes": 566,
"promised_arrival_iso": "2026-05-11T15:00:00+05:30",
"actual_arrival_iso": "2026-05-11T15:34:00+05:30",
"stops_completed": 1,
"states_traversed": ["TS", "AP", "KA"],
"tolls_paid_inr": 1245,
"currency": "INR",
"fare_breakdown_total_inr": 13800,
"rider_tip_inr": 0,
"ratings_pending": true,
"notes": ""
}
Status enum: completed | cancelled_by_user | cancelled_by_driver | failed | rerouted_with_extra_charge | partial_completion_user_drop_early
8. WIDGET
WIDGET TYPE: intercity_ride_options
SOURCE: src/widgets/types.ts
TYPE NAME: IntercityRideOptionsPayload
RENDERED IN: components/widgets/IntercityRideOptionsWidget.tsx
Default: 3 stacked rows showing vehicle_kind, arrival_eta, fare with allowance + toll breakdown summary, key amenities, FASTag adequacy badge. Tap row → confirmation card with full fare breakdown including state-border + night-halt lines → "Book". Then IntercityTrackingCard with leg progress + state-crossing indicators.
9. CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
get_intercity_estimates |
60s | demand moves slower than intracity |
track_intercity_ride |
0s | always live |
book_intercity_ride |
0s | |
cancel_intercity_ride |
0s | |
update_intercity_stops |
0s | |
| Failure responses | 0s |
10. ERROR CODES
| Code | HTTP | Meaning | TOMO behavior |
|---|---|---|---|
NO_DRIVERS_AVAILABLE |
503 | none with valid permit + capacity | retry with delay or fall back |
OUT_OF_SERVICE_AREA |
400 | pickup or drop outside coverage | surface |
STATE_NOT_COVERED_BY_PERMIT |
400 | partner has no permit for required state | surface, suggest alternate |
OPTION_EXPIRED |
410 | ride_option_token invalid | re-quote |
PAYMENT_DECLINED |
402 | gateway rejection | surface |
OTP_FAILED |
401 | OTP-at-pickup mismatch | surface |
RIDE_NOT_FOUND |
404 | ride_ref doesn't exist | surface |
ALREADY_CANCELLED |
409 | duplicate cancel | idempotent return |
DRIVER_FATIGUE_LIMIT_REACHED |
503 | MV Act drive-hours exceeded | partner reassigns |
WEATHER_BLOCK |
503 | route flagged unsafe (cyclone, flood) | suggest reschedule |
FASTAG_INSUFFICIENT |
400 | route requires FASTag, balance low | surface top-up CTA |
STOP_OUT_OF_RANGE |
400 | intermediate stop > 50km off route | reject or re-quote |
11. SANDBOX → PRODUCTION CHECKLIST
[ ] All §2 inputs validated, request_id echoed
[ ] get_intercity_estimates returns ≥3 options for "Hyderabad → Bangalore, 4 pax, 6 bags"
[ ] All §4 required fields populated with REAL data
[ ] driver_kyc + vehicle_meta truthful + verifiable on demand
[ ] permit_states_covered ⊇ states_crossed validated
[ ] all_india_tourist_permit OR equivalent verified for multi-state
[ ] fitness_certificate + insurance + PUC + permit numbers all valid
[ ] book_intercity_ride returns ride_ref + driver assignment within SLA
[ ] track_intercity_ride returns location ≤10s old + leg progress accurate
[ ] cancel respects free_cancel_until_iso absolute window
[ ] update_intercity_stops handles ≥2 stops with correct fare recalc
[ ] CPC webhook arrives within 60s of ride completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] Trip share URL works for ≥4h post-completion (vs 2h intracity)
[ ] SOS button tested with TOMO ops monitoring
[ ] Highway-assist telematics sample data shared for 100-call test
[ ] Fatigue compliance check tested on 14h+ trip simulation
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] Aggregator + tourist permit certificates uploaded for every state served
12. ANTI-FABRICATION RULES
RULE 1 — No paid placement signals.
RULE 2 — No fake driver ratings.
rating_avg = unrounded float from real ride feedback. TOMO samples 1% rides.
RULE 3 — No fake intercity_rides_completed inflation.
TOMO compares stated count against partner's CPC ledger; mismatch >5% = breach.
RULE 4 — Vehicle plate must match the actual vehicle dispatched.
plate_masked at booking → must match vehicle that arrives.
RULE 5 — Fare displayed must be honored.
is_upfront_fare=true means fare_locked_until_iso. Post-trip price hike (other
than legitimate detour or extra stop) = breach.
RULE 6 — Driver KYC + permit claims must be verifiable.
TOMO ops can request KYC + permit docs for any driver_id at any time. Failure
to produce within 48h = breach.
RULE 7 — Fatigue compliance is non-negotiable.
cumulative_drive_minutes_today must be reported truthfully. MV Act caps drive
hours; partners ignoring this = breach.
RULE 8 — No surge gaming on intercity.
Intercity fares are typically upfront, not surge-driven. Any post-quote upward
fare adjustment requires a specific itemized line-item (extra stop, route change,
state border, etc.) — surge_multiplier is NOT a valid intercity field.
RULE 9 — Cancel charges must match displayed thresholds.
free_cancel_until_iso enforced server-side. Charging within window = breach.
RULE 10 — No commission-based response shaping.
Same trip on TOMO and on partner's app must yield same fare.
RULE 11 — No state-border charge fabrication.
state_border_charge_inr must be 0 if states_crossed has 1 element.
Inventing border charges for same-state trips = breach.
RULE 12 — No driver swap mid-trip without alert.
Any change of driver_id mid-trip must trigger a ride_safety alert + user
consent. Silent swap = breach.
VERSION HISTORY
v1.0.0 — 2026-05-10 — Initial spec