T
TOMO
Developer Docs
BETA These docs are under partner review. Some features described are roadmap items, not yet shipped. Verify against your sandbox before relying on any contract.
● DRAFTv1.0.0mobility.book_outstation_package

mobility.book_outstation_package — Full Intent Specification

INTENT NAMESPACE: mobility
INTENT NAME:      book_outstation_package
FULL ID:          mobility.book_outstation_package
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

Outstation packages are multi-day cab+driver bookings with itinerary-driven KM allowances, daily DA, night halts, and sightseeing flexibility. They differ from intercity (one A→B trip) and from self-drive (no driver) and from chauffeur-hourly (single city). Locked structural shape: (a) itinerary block with day-by-day plan; (b) package_kind enum with fixed allowances; (c) per-day KM cap with overage rate; (d) driver allowance + night halt accumulate per day; (e) longer trip exposure → safety weight 0.30, taste up because vehicle becomes the user's home for days.


1. NATURAL LANGUAGE COVERAGE

Classifies IN

  • "Goa 4N5D package with cab"
  • "outstation cab to Tirupati 2N3D"
  • "Coorg package 3 nights with driver"
  • "weekend Hampi cab and stay"
  • "Munnar trip 2 nights with cab"
  • "outstation Innova for 5 days Hyderabad to Bangalore via Mysore"
  • "Tirupati Tirumala darshan package round trip"
  • "5 day cab booking with sightseeing"
  • "Pondicherry trip 4 nights cab"

Classifies OUT — borderline NO

  • "Hyderabad to Bangalore one way" → mobility.book_intercity_ride
  • "self-drive Goa 4 days" → mobility.book_self_drive
  • "chauffeur for full day Bangalore" → mobility.book_chauffeur_hourly
  • "weekend road trip self-drive" → mobility.book_self_drive
  • "package tour with hotel" → travel.book_package

MULTI-INTENT TRIGGERS

  • "Goa 4N5D cab and book hotel near Calangute" → mobility.book_outstation_package + travel.book_hotel
  • "Tirupati cab 2N3D and book darshan slot" → mobility.book_outstation_package + travel.book_tour_guide
  • "outstation cab 5 days and FASTag top-up" → mobility.book_outstation_package + pay.fastag_topup

2. INPUT — TOMO → PROVIDER

{
  "intent":          "mobility.book_outstation_package",
  "intent_version":  "v1.0.0",
  "request_id":      "req_outs_2k9p_2026-05-10T07:30:00Z",
  "user_session_id": "anon_user_token_or_uid",

  "package_kind":    "round_trip_with_sightseeing",
  "origin_city": {
    "lat":            17.4435,
    "lng":            78.3772,
    "address":        "HITEC City Main Road, Madhapur",
    "city":           "Hyderabad",
    "state_code":     "TS",
    "country_code":   "IN"
  },

  "primary_destination_city": {
    "lat":            15.2993,
    "lng":            74.1240,
    "address":        "Calangute Beach Road, Goa",
    "city":           "Goa",
    "state_code":     "GA",
    "country_code":   "IN"
  },

  "itinerary": [
    {
      "day_index":               1,
      "date_iso":                "2026-05-11",
      "from_city":               "Hyderabad",
      "to_city":                 "Goa",
      "expected_distance_km":    640,
      "expected_drive_hours":    13,
      "stops_planned":           ["Hubli food break"],
      "night_halt_city":         "Goa",
      "is_drive_day":            true
    },
    {
      "day_index":               2,
      "date_iso":                "2026-05-12",
      "from_city":               "Goa",
      "to_city":                 "Goa",
      "expected_distance_km":    80,
      "expected_drive_hours":    4,
      "stops_planned":           ["Calangute", "Baga", "Anjuna"],
      "night_halt_city":         "Goa",
      "is_drive_day":            false
    },
    {
      "day_index":               3,
      "date_iso":                "2026-05-13",
      "from_city":               "Goa",
      "to_city":                 "Goa",
      "expected_distance_km":    120,
      "expected_drive_hours":    5,
      "stops_planned":           ["Old Goa Basilica", "Dudhsagar Falls"],
      "night_halt_city":         "Goa",
      "is_drive_day":            false
    },
    {
      "day_index":               4,
      "date_iso":                "2026-05-14",
      "from_city":               "Goa",
      "to_city":                 "Goa",
      "expected_distance_km":    60,
      "expected_drive_hours":    3,
      "stops_planned":           ["Palolem"],
      "night_halt_city":         "Goa",
      "is_drive_day":            false
    },
    {
      "day_index":               5,
      "date_iso":                "2026-05-15",
      "from_city":               "Goa",
      "to_city":                 "Hyderabad",
      "expected_distance_km":    640,
      "expected_drive_hours":    13,
      "stops_planned":           ["Hubli"],
      "night_halt_city":         "none",
      "is_drive_day":            true
    }
  ],

  "trip_duration_days":      5,
  "trip_nights_count":       4,
  "trip_starts_iso":         "2026-05-11T05:00:00+05:30",
  "trip_ends_iso":           "2026-05-15T22:00:00+05:30",

  "party": {
    "passenger_count":  4,
    "luggage_pieces":   8,
    "luggage_size":     "checkin",
    "minor_count":      1,
    "senior_count":     1
  },

  "preferences": {
    "vehicle_kinds_acceptable":   ["sedan_intercity", "suv_intercity", "tempo_traveller"],
    "budget_band":                "good",
    "budget_max_inr":              45000,
    "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", "hi-IN"],
    "music_system_required":       true,
    "include_recliner_seats":      true
  },

  "trip_intent_meta": {
    "expected_total_distance_km":       1540,
    "expected_states_crossed":          ["TS", "KA", "GA"],
    "involves_highway":                 true,
    "involves_offroad":                 false,
    "is_overnight_drives_count":        2,
    "is_pilgrim_trip":                  false,
    "purpose":                          "leisure_family"
  },

  "context": {
    "user_locale":          "en-IN",
    "user_currency_pref":   "INR",
    "trust_signals": {
      "is_repeat_customer":          true,
      "prior_outstation_with_partner": 1,
      "user_account_age_days":       312,
      "fastag_present":              true,
      "fastag_balance_inr":          1840
    }
  }
}
Field Type Constraint Notes
intent string REQUIRED, equals "mobility.book_outstation_package"
package_kind enum REQUIRED, see §5
origin_city.state_code string REQUIRED
primary_destination_city.state_code string REQUIRED
itinerary array REQUIRED, ≥1 one entry per day
itinerary[].day_index int REQUIRED, ≥1, contiguous
itinerary[].date_iso ISO_DATE REQUIRED
itinerary[].is_drive_day bool REQUIRED drives DA + night halt math
itinerary[].night_halt_city string REQUIRED, may be "none"
itinerary[].expected_distance_km float REQUIRED
trip_duration_days int REQUIRED, ≥1
trip_nights_count int REQUIRED, ≥0
trip_starts_iso ISO_DATETIME REQUIRED
trip_ends_iso ISO_DATETIME REQUIRED must be > trip_starts
party.minor_count int REQUIRED, ≥0
party.senior_count int REQUIRED, ≥0
preferences.driver_must_speak_locales array REQUIRED, ≥1
preferences.music_system_required bool REQUIRED
preferences.include_recliner_seats bool REQUIRED
trip_intent_meta.is_pilgrim_trip bool REQUIRED drives behavior signals (no alcohol etc.)
trip_intent_meta.is_overnight_drives_count int REQUIRED, ≥0

Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.


3. PROVIDER TOOLS

Tool 1: get_outstation_package_estimates

PURPOSE:        return package options across vehicle kinds for itinerary
INPUT:          §2 request body
OUTPUT:         { options: OutstationPackageOption[], result_token, expires_at }
SLA:            p50 < 800ms, p95 < 2000ms
RATE LIMIT:     ≤ 1/sec per user

Tool 2: book_outstation_package

PURPOSE:        commit package
INPUT:          { option_id, payment_token, request_id, idempotency_key, user_phone, otp_required }
OUTPUT:         { booking_ref, status, driver, vehicle, fare_quote, allowance_breakdown, day_by_day_kit }
SLA:            p95 < 6000ms
IDEMPOTENCY:    REQUIRED on idempotency_key

Tool 3: track_outstation_package

PURPOSE:        live state across the trip with day-by-day progress
INPUT:          { booking_ref, request_id }
OUTPUT:         OutstationPackageTrack (§4)
SLA:            p95 < 500ms
RATE LIMIT:     ≤ 1 every 30s

Tool 4: cancel_outstation_package

PURPOSE:        cancel before trip starts OR mid-trip
INPUT:          { booking_ref, reason, request_id }
OUTPUT:         { status, cancellation_charge_inr, refund_amount_inr, cancellation_window_kind }
SLA:            p95 < 2000ms

Tool 5: update_itinerary

PURPOSE:        modify day plan (add stop, change night halt, etc.)
INPUT:          { booking_ref, day_index, updated_day_plan, request_id }
OUTPUT:         { revised_fare_inr, revised_distance_km, status }
SLA:            p95 < 1500ms

Tool 6: mark_day_complete

PURPOSE:        partner closes a day's leg
INPUT:          { booking_ref, day_index, day_summary, request_id }
OUTPUT:         { acknowledged: true, day_completion_iso, partial_fare_settled_inr }
SLA:            p95 < 1500ms

Tool 7: rate_outstation_package

PURPOSE:        post-trip rating
INPUT:          { booking_ref, rating_5star, comment, tip_inr, request_id }
OUTPUT:         { acknowledged: true }
SLA:            p95 < 800ms

Tool 8: share_trip_status

PURPOSE:        tokenized live tracking URL
INPUT:          { booking_ref, recipient_phone_optional, request_id }
OUTPUT:         { share_url, expires_at }
SLA:            p95 < 500ms

All eight REQUIRED.


4. RESPONSE SHAPE

OutstationPackageOption (returned by get_outstation_package_estimates)

id:                               string, REQUIRED
option_token:                     string, REQUIRED
expires_at:                       ISO_DATETIME, REQUIRED

vehicle_kind:                     STRICT ENUM, REQUIRED
vehicle_class:                    STRICT ENUM, REQUIRED
display_label:                    string, REQUIRED
seat_capacity:                    int, REQUIRED, ≥1
luggage_capacity:                 STRICT ENUM, REQUIRED

availability:
  trip_dispatch_iso:              ISO_DATETIME, REQUIRED
  driver_pre_dispatch_minutes:    int, REQUIRED
  alternate_pickup_options:       array, REQUIRED, may be empty

fare:
  total_inr:                      INR_INTEGER, REQUIRED
  base_per_day_inr:               INR_INTEGER, REQUIRED
  base_per_km_inr:                float, REQUIRED
  total_billed_km:                int, REQUIRED
  included_km_total:              int, REQUIRED
  per_km_overage_inr:             float, REQUIRED
  driver_allowance_inr_per_day:   INR_INTEGER, REQUIRED
  driver_allowance_total_inr:     INR_INTEGER, REQUIRED
  night_halt_charge_inr_per_night: INR_INTEGER, REQUIRED
  night_halt_charge_total_inr:    INR_INTEGER, REQUIRED
  night_halt_count:               int, REQUIRED, ≥0
  toll_inr:                       INR_INTEGER, REQUIRED
  toll_count:                     int, REQUIRED, ≥0
  state_border_charge_inr:        INR_INTEGER, REQUIRED
  state_border_count:             int, REQUIRED, ≥0
  highway_charge_inr:             INR_INTEGER, REQUIRED
  ac_charge_inr:                  INR_INTEGER, REQUIRED
  parking_charge_inr:             INR_INTEGER, REQUIRED
  late_night_drive_inr:           INR_INTEGER, REQUIRED
  platform_fee_inr:               INR_INTEGER, REQUIRED
  gst_inr:                        INR_INTEGER, REQUIRED
  rider_tip_optional_inr:         INR_INTEGER, REQUIRED
  fare_breakdown_text:            string, REQUIRED
  is_upfront_fare:                boolean, REQUIRED
  fare_locked_until_iso:          ISO_DATETIME, REQUIRED
  return_trip_empty_pricing:      boolean, REQUIRED            # for one_way packages

day_by_day_breakdown:
  - day_index:                    int, REQUIRED
    distance_km:                  float, REQUIRED
    drive_hours:                  float, REQUIRED
    is_drive_day:                 boolean, REQUIRED
    night_halt_city:              string, REQUIRED
    daily_inr:                    INR_INTEGER, REQUIRED        # day's portion of total
    sightseeing_supported:        boolean, REQUIRED
    additional_stops_allowed:     int, REQUIRED, ≥0

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
  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
  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
  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
  outstation_packages_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
  multi_day_trip_certified:       boolean, REQUIRED            # partner-internal multi-day rating

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

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
  multi_day_relief_driver_available: boolean, REQUIRED         # if trip > 8h drive on any day

route_quality:
  estimated_total_distance_km:    float, REQUIRED
  estimated_total_duration_min:   int, REQUIRED
  total_drive_days:               int, REQUIRED
  total_sightseeing_days:         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

cancellation:
  free_cancel_until_iso:          ISO_DATETIME, REQUIRED
  cancel_charge_within_72h_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
  partial_completion_refund_policy: STRICT ENUM, REQUIRED      # see §5
  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

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_outstation_volume_30d:  int, REQUIRED, ≥0
  partner_outstation_complete_rate_30d: float, REQUIRED, 0-1

OutstationPackageTrack (returned by track_outstation_package)

booking_ref:                      string, REQUIRED
status:                           STRICT ENUM, REQUIRED
status_updated_iso:               ISO_DATETIME, REQUIRED
status_history:                   array, REQUIRED, ≥1

trip_progress:
  current_day_index:              int, REQUIRED, ≥0
  total_days:                     int, REQUIRED
  days_completed:                 int, REQUIRED, ≥0
  km_traveled_so_far:             float, REQUIRED, ≥0
  current_leg_distance_remaining_km: float, REQUIRED
  next_night_halt_city:           string, REQUIRED
  itinerary_compliance:           STRICT ENUM, REQUIRED        # see §5

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
  cumulative_drive_minutes_trip:  int, REQUIRED, ≥0

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_next_night_halt_minutes:     int, REQUIRED
  revised_total_fare_inr:         INR_INTEGER, REQUIRED
  detour_minutes_today:           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
  next_toll_amount_inr:           INR_INTEGER, REQUIRED
  user_fastag_balance_sufficient_for_remaining_tolls: boolean, REQUIRED
  cumulative_toll_paid_inr:       INR_INTEGER, REQUIRED, ≥0

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_outstation_volume_30d | partner_paid_for_top_listing |
fake_complete_rate_30d | hidden_da_charge_inr | undocumented_night_halt_charge

5. CONTROLLED VOCABULARIES

package_kind

round_trip_with_sightseeing | round_trip_no_sightseeing |
one_way_with_sightseeing | one_way_no_sightseeing |
pilgrim_circuit | adventure_circuit | beach_circuit |
hill_station_circuit | wildlife_circuit | custom_itinerary

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

OutstationPackageOption.luggage_capacity

small | medium | large | xl | xxl

vehicle_meta.fuel_kind

petrol | diesel | cng | lpg | ev_full | hybrid | bs6_petrol | bs6_diesel

vehicle_meta.emission_norm

bs3 | bs4 | bs6 | ev | unknown_legacy

vehicle_meta.permit_kind

tourist | all_india_tourist | contract_carriage

Outstation REQUIRES tourist | all_india_tourist | contract_carriage. Aggregator-only permits NOT valid for multi-day cross-state.

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+

cancellation.partial_completion_refund_policy

pro_rata_remaining_days | flat_50pct_unused_days |
flat_70pct_unused_days | no_refund_after_day_one | full_refund_until_day_one

OutstationPackageTrack.status

booked | scheduled | driver_assigned | driver_dispatched |
trip_started_day_1 | day_in_progress | day_complete |
night_halt | trip_complete | cancelled_by_user |
cancelled_by_driver | partial_completion | failed |
itinerary_modified

OutstationPackageTrack.location.status

heading_to_pickup | at_pickup | trip_in_progress |
at_intermediate_stop | at_sightseeing_stop |
crossing_state_border | nearby_night_halt | at_night_halt |
at_drop

OutstationPackageTrack.trip_progress.itinerary_compliance

fully_compliant | minor_deviation_under_30km | major_deviation_over_30km |
day_skipped_with_consent | day_skipped_without_consent

cancel_outstation_package.reason

user_changed_mind | weather_cancellation | driver_unavailable |
vehicle_breakdown | safety_concern | medical_emergency |
no_longer_needed | found_alternative | itinerary_unworkable | other

context.trip_intent_meta.purpose

leisure_family | leisure_friends | leisure_solo | leisure_couple |
pilgrimage | wedding_event | business_trip | medical_trip |
school_trip | corporate_offsite | other

6. TTBS DIMENSIONS

Per-domain weights (locked; outstation override)

mobility (outstation_package): { time: 0.20, taste: 0.20, budget: 0.30, safety: 0.30 }

Time drops (multi-day, no minute-precision pressure). Taste up (vehicle becomes home). Safety strong (highway exposure × multi-day).

TIME

SIGNALS USED:
  - availability.trip_dispatch_iso ≤ trip_starts_iso   HARD FILTER
  - driver_pre_dispatch_minutes (low=better)           weight 0.10
  - route_quality.estimated_total_duration_min         weight 0.30
  - cancellation.refund_processing_days                weight 0.10
  - day_by_day_breakdown sightseeing_supported on requested days HARD FILTER for tight itineraries

USER BAND HANDLING:
  - "morning departure" preference shifts pickup_minutes weight

TASTE

SIGNALS USED:
  - driver_meta.rating_avg                              weight 0.25
  - vehicle.year_of_manufacture                         weight 0.10
  - vehicle_amenities match w/ user prefs               weight 0.25
  - vehicle_amenities.recliner_seats (multi-day comfort) weight 0.10
  - vehicle_amenities.fridge_in_cabin (luxury/great)    weight 0.10
  - driver languages match user_locale + states crossed weight 0.10
  - driver_meta.multi_day_trip_certified                weight 0.10

HARD FILTER:
  - ac_required + ac=false → drop
  - is_pilgrim_trip + driver doesn't speak local pilgrim_locale → 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 / tempo_traveller_premium
  - fare.is_upfront_fare=true                           weight 0.20
  - fare.included_km_total vs expected_total_distance_km weight 0.20
  - fare.return_trip_empty_pricing=false (better)       weight 0.10
  - fastag_topup_recommended_inr (lower)                weight 0.10

HARD FILTERS:
  - fare.total_inr > preferences.budget_max_inr → drop
  - day_by_day_breakdown.daily_inr exceeds 1.5x average for any single day → flag (likely surge gaming)

USER BAND HANDLING:
  - leisure_family deweights ok; pilgrim trip stays cost-conscious

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.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.multi_day_relief_driver_available
      (if any drive_day > 8h)                          weight 0.20
  - driver_meta.outstation_packages_completed (≥10)     weight 0.10
  - driver_meta.highway_experience_years (≥5)           weight 0.10
  - driver_meta.defensive_driving_certified             weight 0.05
  - driver_meta.multi_day_trip_certified                weight 0.10
  - driver_meta.female_driver
      (boosted if female_driver_required)              weight 0.10
  - is_overnight_drives_count > 0 → safety scales 1.5x

HARD FILTERS:
  - female_driver_required → drop male drivers
  - states_crossed not covered by permit → drop
  - any drive_day > 12h AND multi_day_relief_driver_available=false → drop
  - is_pilgrim_trip AND alcohol_consumption_history detected (partner-tracked) → drop

Hidden ranking factor

information_completeness_score weight 0.10.

FASTag check

Surface FASTag balance vs estimated_toll_total_inr at option-card level. For multi-day trips, also surface day-by-day toll preview.


7. COMPLETION CONTRACT

POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
X-TOMO-Timestamp: <ms>
X-TOMO-Signature: sha256=<hex>

{
  "intent":            "mobility.book_outstation_package",
  "intent_version":    "v1.0.0",
  "external_id":       "OLA-OUTS-XYZ",
  "amount_inr":         42500,
  "closed_at":         "2026-05-15T22:14:00+05:30",
  "request_id":        "req_outs_2k9p_...",
  "status":            "completed",
  "booking_ref":       "OLA-OUTS-XYZ",
  "trip_started_at":   "2026-05-11T05:08:00+05:30",
  "trip_completed_at": "2026-05-15T22:00:00+05:30",
  "days_completed":    5,
  "total_distance_traveled_km": 1614,
  "states_traversed":     ["TS", "KA", "GA"],
  "tolls_paid_inr":       2840,
  "night_halts_paid":     4,
  "driver_allowance_paid_inr": 2500,
  "currency":          "INR",
  "fare_breakdown_total_inr": 42500,
  "rider_tip_inr":       1500,
  "ratings_pending":     true,
  "notes":              ""
}

Status enum: completed | cancelled_by_user | cancelled_by_driver | failed | partial_completion_user_drop_early | extended_with_extra_charge | itinerary_changed_with_consent


8. WIDGET

WIDGET TYPE:        outstation_package_options
SOURCE:             src/widgets/types.ts
TYPE NAME:          OutstationPackageOptionsPayload
RENDERED IN:        components/widgets/OutstationPackageOptionsWidget.tsx

Default: 3 stacked rows showing vehicle_kind, total trip duration, fare with day-count + DA + night-halt badge, key amenities, FASTag adequacy. Tap row → confirmation card with day-by-day fare breakdown timeline → "Book". Then OutstationTrackingCard with day-by-day progress strip + current leg + state-crossing indicators.


9. CACHING POLICY

Call TTL Rationale
get_outstation_package_estimates 300s demand moves slowly for multi-day plans
track_outstation_package 0s always live
book_outstation_package 0s
cancel_outstation_package 0s
update_itinerary 0s
mark_day_complete 0s
Failure responses 0s

10. ERROR CODES

Code HTTP Meaning TOMO behavior
NO_DRIVERS_AVAILABLE 503 none with multi-day permit + capacity retry or fall back
OUT_OF_SERVICE_AREA 400 origin or destination outside coverage surface
STATE_NOT_COVERED_BY_PERMIT 400 permit doesn't cover required state surface, suggest alternate
OPTION_EXPIRED 410 option_token invalid re-quote
PAYMENT_DECLINED 402 gateway rejection surface
BOOKING_NOT_FOUND 404 booking_ref doesn't exist surface
ALREADY_CANCELLED 409 duplicate cancel idempotent return
DRIVER_FATIGUE_LIMIT_REACHED 503 MV Act drive-hours exceeded partner reassigns or relief driver
WEATHER_BLOCK 503 route flagged unsafe suggest reschedule
FASTAG_INSUFFICIENT 400 route requires FASTag, balance low top-up CTA
ITINERARY_INFEASIBLE 400 day plan exceeds drive-hours cap surface alternate
DAY_INDEX_OUT_OF_RANGE 400 update_itinerary invalid day_index surface

11. SANDBOX → PRODUCTION CHECKLIST

[ ] All §2 inputs validated, request_id echoed
[ ] get_outstation_package_estimates returns ≥3 options for "Hyderabad → Goa 4N5D"
[ ] All §4 required fields populated with REAL data
[ ] driver_kyc + vehicle_meta truthful + verifiable
[ ] permit_states_covered ⊇ states_crossed validated
[ ] all_india_tourist_permit OR equivalent verified for multi-state
[ ] fitness_certificate + insurance + PUC + permit valid through trip_ends_iso
[ ] book_outstation_package returns booking_ref + driver assignment within SLA
[ ] track_outstation_package returns location ≤30s old + day progress accurate
[ ] cancel respects free_cancel_until_iso absolute window
[ ] update_itinerary handles ≥2 day changes with correct fare recalc
[ ] mark_day_complete fires on every completed day with summary
[ ] CPC webhook arrives within 60s of trip completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] Trip share URL works for ≥7 days post-completion
[ ] SOS button tested with TOMO ops monitoring
[ ] Fatigue compliance check tested on 14h+ day simulation
[ ] multi_day_relief_driver_available tested on >8h drive day
[ ] partner_outstation_complete_rate_30d audited against TOMO sample
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] Tourist + aggregator permit certificates uploaded for every state

12. ANTI-FABRICATION RULES

RULE 1 — No paid placement signals.

RULE 2 — No fake driver ratings.

RULE 3 — No fake outstation_packages_completed inflation.
  TOMO compares stated count against partner's CPC ledger; mismatch >5% = breach.

RULE 4 — No fake complete_rate_30d.
  Rate must come from partner's CPC ledger of completed multi-day trips.
  TOMO samples 1% trips and validates against day-by-day completion records.

RULE 5 — Fare displayed must be honored.
  is_upfront_fare=true means fare_locked_until_iso. Per-km overage is the ONLY
  legitimate post-trip increase (and must be audit-trail-linked to actual
  km_traveled_so_far in track payload).

RULE 6 — Day-by-day fare must add to total.
  Sum of day_by_day_breakdown.daily_inr must equal fare.total_inr (within
  ±50 INR rounding). Mismatch = pricing fraud.

RULE 7 — Driver KYC + permit claims must be verifiable.

RULE 8 — Fatigue compliance is non-negotiable.
  cumulative_drive_minutes_today must be reported truthfully. MV Act caps at
  10h continuous; partners ignoring this = breach.

RULE 9 — Cancel charges must match displayed thresholds.
  Each tier (72h, 24h, 2h) of cancellation must hold to the displayed value.

RULE 10 — No commission-based response shaping.

RULE 11 — Night halt charged only on actual halt nights.
  night_halt_count must equal nights between trip_starts and trip_ends where
  vehicle remained outside origin city. Charging for nights vehicle returned
  home = breach.

RULE 12 — Driver allowance charged only on actual drive days.
  driver_allowance_total_inr ≤ allowance_per_day × drive_days_actual. Charging
  full DA for non-drive days = breach.

RULE 13 — No silent driver swap mid-trip.
  Any driver_id change mid-trip must trigger user notification + consent.

RULE 14 — Itinerary deviation > 30km requires user consent.
  itinerary_compliance=major_deviation_over_30km without recorded user consent
  = breach.

RULE 15 — Pilgrim trip constraints.
  is_pilgrim_trip=true means partner ensures non-alcohol-history driver.
  Partner falsifying alcohol-history clearance = severe breach.

VERSION HISTORY

v1.0.0 — 2026-05-10 — Initial spec