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_ev_with_charge_planning

mobility.book_ev_with_charge_planning — Full Intent Specification

INTENT NAMESPACE: mobility
INTENT NAME:      book_ev_with_charge_planning
FULL ID:          mobility.book_ev_with_charge_planning
VERSION:          v1.0.0
STATUS:           draft
LAST UPDATED:     2026-05-10
TTBS WEIGHTS:     time 0.30 · taste 0.10 · budget 0.20 · safety 0.40

EV-with-charge-planning is a journey intent where the vehicle is electric AND the route is long enough that one or more charging stops must be planned, scheduled, and verified before booking. It applies across journey kinds (self-drive EV, EV with driver intercity, EV outstation) — the charging logic is the locked novelty. Structural shape: (a) journey_kind enum determines whether driver_meta + party are present; (b) charge_plan block with charge_stops[] is first-class — each stop has charger_kind, expected SoC at arrival, expected charge minutes, contingency charger; (c) battery_telemetry in track is mandatory live signal; (d) safety weight 0.40 (highest of any mobility intent — battery range anxiety + charger reliability are first-order safety concerns).


1. NATURAL LANGUAGE COVERAGE

Classifies IN

  • "EV cab to Tirupati with charging stops"
  • "self-drive EV Hyderabad to Bangalore"
  • "rent Tata Nexon EV for weekend with charge planning"
  • "EV intercity to Vijayawada plan the chargers"
  • "MG ZS EV outstation to Coorg, plan charging"
  • "electric car for Hyderabad to Mumbai with stops"
  • "EV with driver to Goa, charging route"
  • "long range EV trip with charge planning"
  • "BluSmart EV intercity"

Classifies OUT — borderline NO

  • "EV cab to airport" → mobility.book_airport_transfer (route too short for charge planning)
  • "EV auto to MG Road" → mobility.book_intracity_ride (intra-city, no plan needed)
  • "rent EV scooter" → mobility.book_two_wheeler_rental
  • "buy EV" → no intent (informational)
  • "install EV charger at home" → auto.book_ev_charger_install

MULTI-INTENT TRIGGERS

  • "EV intercity Hyderabad to Bangalore and book hotel" → mobility.book_ev_with_charge_planning + travel.book_hotel
  • "EV self-drive weekend and FASTag top-up" → mobility.book_ev_with_charge_planning + pay.fastag_topup
  • "EV outstation to Goa 4N5D with sightseeing" → mobility.book_ev_with_charge_planning (uses outstation shape internally) + nothing else if entirely EV

2. INPUT — TOMO → PROVIDER

{
  "intent":          "mobility.book_ev_with_charge_planning",
  "intent_version":  "v1.0.0",
  "request_id":      "req_evcp_8h3k_2026-05-10T08:00:00Z",
  "user_session_id": "anon_user_token_or_uid",

  "journey_kind":    "ev_with_driver_intercity",

  "origin": {
    "lat":            17.4435,
    "lng":            78.3772,
    "address":        "HITEC City, Hyderabad",
    "city":           "Hyderabad",
    "state_code":     "TS",
    "country_code":   "IN",
    "place_kind":     "office"
  },

  "destination": {
    "lat":            12.9716,
    "lng":            77.5946,
    "address":        "MG Road, Bangalore",
    "city":           "Bangalore",
    "state_code":     "KA",
    "country_code":   "IN",
    "place_kind":     "hotel"
  },

  "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,

  "user_driving_profile": {
    "user_age":                       28,
    "license_state_code":             "TS",
    "license_class_includes_lmv":     true,
    "license_held_for_years":         6,
    "license_verified_with_partner":  false,
    "ev_familiarity_level":           "moderate",
    "international_license":          false
  },

  "party": {
    "passenger_count":  3,
    "luggage_pieces":   4,
    "luggage_size":     "checkin",
    "minor_count":      0,
    "senior_count":     0
  },

  "preferences": {
    "vehicle_kinds_acceptable":   ["ev_sedan", "ev_suv", "ev_premium_sedan"],
    "ev_min_battery_capacity_kwh": 50,
    "ev_min_real_range_km":       400,
    "max_charge_stops":           2,
    "max_total_charge_minutes":   60,
    "preferred_charger_kinds":    ["ccs2_fast", "ccs2_ultrafast"],
    "acceptable_charger_kinds":   ["ccs2_fast", "ccs2_ultrafast", "type2_ac"],
    "min_charger_kw":             50,
    "min_arrival_battery_pct":    20,
    "target_arrival_battery_pct": 30,
    "budget_band":                "good",
    "budget_max_inr":              16000,
    "ac_required":                 true,
    "female_driver_required":      false,
    "wheelchair_accessible_required": false,
    "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,
    "estimated_climbs_meters":   180,
    "expected_average_speed_kmh": 65,
    "expected_temperature_celsius": 32,
    "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"],
    "is_overnight":              false,
    "is_late_night_departure":   false,
    "is_late_night_arrival":     false
  },

  "context": {
    "user_locale":          "en-IN",
    "user_currency_pref":   "INR",
    "trip_purpose":         "leisure",
    "trust_signals": {
      "is_repeat_customer":          true,
      "prior_ev_journeys_with_partner": 2,
      "user_account_age_days":       312,
      "fastag_present":              true,
      "fastag_balance_inr":          1840
    }
  }
}
Field Type Constraint Notes
intent string REQUIRED, equals "mobility.book_ev_with_charge_planning"
journey_kind enum REQUIRED, see §5 switches whether driver_meta is present
origin.state_code string REQUIRED
destination.state_code string REQUIRED
intermediate_stops array REQUIRED, may be empty
trip_kind enum REQUIRED, STRICT one_way | round_trip
scheduled_pickup_iso ISO_DATETIME REQUIRED
user_driving_profile.ev_familiarity_level enum REQUIRED, see §5 self-drive only; ignored for chauffeur
preferences.ev_min_battery_capacity_kwh int REQUIRED, ≥0
preferences.ev_min_real_range_km int REQUIRED, ≥0 real-world range per partner cert
preferences.max_charge_stops int REQUIRED, ≥0
preferences.max_total_charge_minutes int REQUIRED, ≥0 total cumulative, all stops
preferences.preferred_charger_kinds array REQUIRED, ≥1 see §5
preferences.acceptable_charger_kinds array REQUIRED, ≥1 superset of preferred
preferences.min_charger_kw int REQUIRED, ≥0
preferences.min_arrival_battery_pct int REQUIRED, 0-100 safety floor
preferences.target_arrival_battery_pct int REQUIRED, 0-100 preferred
route_context.estimated_climbs_meters int REQUIRED, ≥0 drives range estimation
route_context.expected_temperature_celsius int REQUIRED drives battery efficiency
route_context.expected_average_speed_kmh int REQUIRED, ≥0 drives consumption modeling
route_context.states_crossed array REQUIRED, ≥1

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


3. PROVIDER TOOLS

Tool 1: get_ev_journey_estimates

PURPOSE:        return EV journey options with full charge plans
INPUT:          §2 request body
OUTPUT:         { options: EvJourneyOption[], result_token, expires_at }
SLA:            p50 < 1000ms, p95 < 2500ms       (charge planning is compute-intensive)
RATE LIMIT:     ≤ 1/sec per user

Tool 2: book_ev_journey

PURPOSE:        commit a journey with charge plan
INPUT:          { option_id, payment_token, request_id, idempotency_key, user_phone, otp_required, charge_plan_token }
OUTPUT:         { journey_ref, status, vehicle, driver, charge_plan_locked, fare_quote }
SLA:            p95 < 6000ms
IDEMPOTENCY:    REQUIRED on idempotency_key

Tool 3: track_ev_journey

PURPOSE:        live journey state including battery + charge-stop progress
INPUT:          { journey_ref, request_id }
OUTPUT:         EvJourneyTrack (§4)
SLA:            p95 < 500ms
RATE LIMIT:     ≤ 1 every 5s

Tool 4: cancel_ev_journey

PURPOSE:        cancel
INPUT:          { journey_ref, reason, request_id }
OUTPUT:         { status, cancellation_charge_inr, refund_amount_inr }
SLA:            p95 < 2000ms

Tool 5: update_charge_plan

PURPOSE:        re-plan charging mid-trip if charger unavailable / fails
INPUT:          { journey_ref, failed_stop_index, request_id }
OUTPUT:         { revised_charge_stops, revised_total_minutes, revised_fare_inr, status }
SLA:            p95 < 2000ms

Tool 6: confirm_charge_at_stop

PURPOSE:        partner records actual charge session (kWh in, minutes, cost)
INPUT:          { journey_ref, stop_index, kwh_added, charge_minutes, cost_inr, charger_id, request_id }
OUTPUT:         { acknowledged: true, battery_pct_observed, stop_completion_iso }
SLA:            p95 < 1500ms

Tool 7: rate_ev_journey

PURPOSE:        post-journey rating with charge experience axis
INPUT:          { journey_ref, rating_5star, charge_experience_5star, comment, tip_inr, request_id }
OUTPUT:         { acknowledged: true }
SLA:            p95 < 800ms

Tool 8: share_journey_status

PURPOSE:        tokenized live tracking URL (includes battery strip)
INPUT:          { journey_ref, recipient_phone_optional, request_id }
OUTPUT:         { share_url, expires_at }
SLA:            p95 < 500ms

All eight REQUIRED.


4. RESPONSE SHAPE

EvJourneyOption (returned by get_ev_journey_estimates)

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

journey_kind:                     STRICT ENUM, REQUIRED
vehicle_kind:                     STRICT ENUM, REQUIRED       # ev_* values only
vehicle_class:                    STRICT ENUM, REQUIRED
display_label:                    string, REQUIRED            # "MG ZS EV Excite Pro 2024"
make:                             string, REQUIRED
model:                            string, REQUIRED
variant:                          string, REQUIRED
year_of_manufacture:              int, REQUIRED
seat_capacity:                    int, REQUIRED, ≥1
luggage_capacity:                 STRICT ENUM, REQUIRED

ev_specs:
  battery_capacity_kwh:           float, REQUIRED, ≥0
  battery_chemistry:              STRICT ENUM, REQUIRED       # see §5
  warm_state_real_range_km:       int, REQUIRED               # at expected temp + speed
  cold_state_real_range_km:       int, REQUIRED               # for high-altitude or cold ops
  ac_consumption_kwh_per_hour:    float, REQUIRED
  charger_kinds_supported:        array<STRICT ENUM>, REQUIRED, ≥1
  max_charge_kw_dc:               int, REQUIRED, ≥0
  max_charge_kw_ac:               int, REQUIRED, ≥0
  battery_health_pct:             int, REQUIRED, 0-100        # honest, audited
  battery_age_months:             int, REQUIRED, ≥0

start_battery:
  pct_at_dispatch:                int, REQUIRED, 0-100
  km_range_at_dispatch:           int, REQUIRED
  expected_pct_at_pickup:         int, REQUIRED, 0-100        # may be slightly less by drive to pickup

charge_plan:
  total_stops:                    int, REQUIRED, ≥0
  total_charge_minutes:           int, REQUIRED, ≥0
  total_charge_cost_inr:          INR_INTEGER, REQUIRED, ≥0
  total_added_kwh:                float, REQUIRED, ≥0
  arrival_battery_pct:            int, REQUIRED, 0-100        # must be ≥ min_arrival_battery_pct
  arrival_battery_km_range:       int, REQUIRED, ≥0
  charge_stops:                   array, REQUIRED, may be empty
    - stop_index:                 int, REQUIRED, ≥0
      charger_id:                 string, REQUIRED
      charger_brand:              string, REQUIRED
      charger_kind:               STRICT ENUM, REQUIRED
      charger_kw:                 int, REQUIRED, ≥0
      lat:                        float, REQUIRED
      lng:                        float, REQUIRED
      address:                    string, REQUIRED
      city:                       string, REQUIRED
      state_code:                 string, REQUIRED
      arrival_eta_iso:            ISO_DATETIME, REQUIRED
      arrival_battery_pct:        int, REQUIRED, 0-100
      target_battery_pct:         int, REQUIRED, 0-100
      expected_charge_minutes:    int, REQUIRED
      expected_kwh_added:         float, REQUIRED
      expected_cost_inr:          INR_INTEGER, REQUIRED
      charger_compatibility_verified: boolean, REQUIRED
      charger_availability_check_iso: ISO_DATETIME, REQUIRED
      charger_uptime_30d_pct:     float, REQUIRED, 0-1
      backup_charger_within_5km:  boolean, REQUIRED
      backup_charger_id:          string, REQUIRED            # may be empty if backup_charger_within_5km=false
      amenities_at_stop:          array<STRICT ENUM>, REQUIRED, may be empty   # see §5
      stop_kind:                  STRICT ENUM, REQUIRED        # planned_charge | also_food_break | also_washroom

eta:
  pickup_minutes:                 int, REQUIRED
  drive_minutes_total:            int, REQUIRED               # excludes charging
  charge_minutes_total:           int, REQUIRED
  total_minutes:                  int, REQUIRED               # drive + charge
  arrival_eta_iso:                ISO_DATETIME, REQUIRED

fare:
  total_inr:                      INR_INTEGER, REQUIRED
  base_inr:                       INR_INTEGER, REQUIRED
  per_km_inr:                     float, REQUIRED
  total_km_charged:               float, REQUIRED
  charge_cost_inr:                INR_INTEGER, REQUIRED        # who pays = depends on journey_kind
  charge_cost_borne_by:           STRICT ENUM, REQUIRED        # user | partner | shared (see §5)
  driver_allowance_inr:           INR_INTEGER, REQUIRED        # 0 if self_drive
  night_halt_charge_inr:          INR_INTEGER, REQUIRED
  toll_inr:                       INR_INTEGER, REQUIRED
  toll_count:                     int, REQUIRED, ≥0
  state_border_charge_inr:        INR_INTEGER, REQUIRED
  state_border_count:             int, REQUIRED, ≥0
  ac_charge_inr:                  INR_INTEGER, REQUIRED
  late_night_charge_inr:          INR_INTEGER, REQUIRED
  parking_charge_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

vehicle_amenities:
  ac:                             boolean, REQUIRED
  heat_pump:                      boolean, REQUIRED            # better cold-weather efficiency
  preconditioning_supported:      boolean, REQUIRED            # battery preheats while charging
  music_on_demand:                boolean, REQUIRED
  charging_port_inside_cabin:     boolean, REQUIRED            # for user device, not the EV itself
  bottled_water:                  boolean, REQUIRED
  child_seat_available:           boolean, REQUIRED
  child_seat_kind:                STRICT ENUM, REQUIRED
  wheelchair_accessible:          boolean, REQUIRED
  spare_tyre_present:             boolean, REQUIRED
  first_aid_kit_present:          boolean, REQUIRED
  fire_extinguisher_lithium_safe: boolean, REQUIRED            # required for EV

vehicle_meta:
  age_years:                      int, REQUIRED
  fuel_kind:                      STRICT ENUM, REQUIRED        # always ev_full
  emission_norm:                  STRICT ENUM, REQUIRED        # always ev
  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
  permit_kind:                    STRICT ENUM, REQUIRED
  permit_states_covered:          array<string>, REQUIRED, ≥1
  vehicle_color:                  string, REQUIRED
  last_serviced_iso:              ISO_DATE, REQUIRED
  battery_last_diagnostic_iso:    ISO_DATE, REQUIRED
  odometer_reading_km:            int, REQUIRED, ≥0

driver_meta:                       # null/absent if journey_kind = self_drive_ev
  driver_id:                      string, REQUIRED
  display_name:                   string, REQUIRED
  photo_url:                      URL, REQUIRED
  rating_avg:                     float, REQUIRED, 0-5
  ev_journeys_completed:          int, REQUIRED, ≥0            # not just any rides; EV-specific
  ev_certification_held:          boolean, REQUIRED
  partner_account_age_days:       int, REQUIRED, ≥0
  languages_spoken:               array<RFC_3066_LOCALE>, REQUIRED, ≥1
  female_driver:                  boolean, REQUIRED
  age_band:                       STRICT ENUM, REQUIRED
  highway_experience_years:       int, REQUIRED, ≥0
  charge_planning_familiarity:    STRICT ENUM, REQUIRED        # see §5

driver_kyc:                       # null/absent if journey_kind = self_drive_ev
  dl_verified:                    boolean, REQUIRED
  dl_number_masked:               string, REQUIRED
  dl_valid_until_iso:             ISO_DATE, REQUIRED
  background_check_passed:        boolean, REQUIRED
  background_check_iso:           ISO_DATETIME, REQUIRED
  badge_id_displayed:             boolean, REQUIRED
  fatigue_compliance_certified:   boolean, REQUIRED

rider_qualification_for_user:     # populated only if journey_kind = self_drive_ev
  min_user_age_required:          int, REQUIRED, ≥18
  min_license_held_years:         int, REQUIRED, ≥0
  ev_familiarity_required:        STRICT ENUM, REQUIRED
  user_meets_qualification:       boolean, REQUIRED
  qualification_failure_reason:   STRICT ENUM, 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            # null if self_drive
  speed_limit_governing:          boolean, REQUIRED
  highway_assist_telematics:      boolean, REQUIRED
  battery_thermal_warning_alerts: boolean, REQUIRED
  charger_failure_realtime_alert: boolean, REQUIRED            # critical for EV journey
  contingency_tow_to_charger:     boolean, REQUIRED            # if battery fails
  emergency_charger_swap_window_minutes: int, REQUIRED          # SLA for finding alternate

route_quality:
  estimated_distance_km:          float, REQUIRED
  estimated_duration_min:         int, REQUIRED
  highway_kms:                    float, REQUIRED
  inner_road_kms:                 float, REQUIRED
  primary_highway_codes:          array<string>, REQUIRED
  toll_passes:                    array, REQUIRED, may be empty

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

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

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

EvJourneyTrack (returned by track_ev_journey)

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

leg_progress:
  current_leg_index:              int, REQUIRED, ≥0
  total_legs:                     int, REQUIRED, ≥1
  next_charge_stop_index:         int, REQUIRED, ≥-1           # -1 if no more
  next_charge_stop_eta_iso:       ISO_DATETIME, REQUIRED       # may equal future iso
  current_leg_distance_remaining_km: float, REQUIRED

battery_telemetry:
  current_pct:                    int, REQUIRED, 0-100
  current_km_range_remaining:     int, REQUIRED
  predicted_pct_at_next_charger:  int, REQUIRED, 0-100
  predicted_pct_at_destination:   int, REQUIRED, 0-100
  consumption_kwh_per_100km:      float, REQUIRED
  ac_consumption_active:          boolean, REQUIRED
  battery_temperature_celsius:    float, REQUIRED
  battery_thermal_warning_active: boolean, REQUIRED
  range_anxiety_warning_active:   boolean, REQUIRED            # if predicted_pct_at_destination < min_arrival_pct

charge_session:
  active:                         boolean, REQUIRED
  current_charger_id:             string, REQUIRED              # may be empty if not charging
  current_kwh_in:                 float, REQUIRED, ≥0
  current_charge_minutes_so_far:  int, REQUIRED, ≥0
  charge_kw_observed:             int, REQUIRED, ≥0             # 0 if not charging
  expected_completion_iso:        ISO_DATETIME, REQUIRED        # may equal current iso if not charging

driver:                            # null/absent if self_drive
  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

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_charge_stop_minutes:    int, REQUIRED
  to_destination_minutes:         int, REQUIRED
  revised_total_fare_inr:         INR_INTEGER, REQUIRED

ride_safety:
  on_route:                       boolean, REQUIRED
  unusual_stop_detected:          boolean, REQUIRED
  battery_thermal_warning_active: boolean, REQUIRED
  range_anxiety_warning_active:   boolean, REQUIRED
  trip_share_active:              boolean, REQUIRED
  trip_share_url:                 URL, REQUIRED

charge_plan_health:
  charger_at_next_stop_available: boolean, REQUIRED
  charger_at_next_stop_uptime_now: boolean, REQUIRED
  backup_charger_path_active:     boolean, REQUIRED            # true if primary failed and rerouting

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_warm_state_real_range_km | partner_paid_for_top_listing |
fake_battery_health_pct | fake_charger_uptime_30d_pct |
fake_charge_plan_success_rate_30d | hidden_charger_unavailability

5. CONTROLLED VOCABULARIES

journey_kind

self_drive_ev | ev_with_driver_intercity | ev_with_driver_outstation

vehicle_kind

ev_hatchback | ev_sedan | ev_suv | ev_premium_sedan | ev_premium_suv |
ev_luxury_sedan | ev_luxury_suv | ev_xl_van

vehicle_class

economy | comfort | premium | luxury | xl

EvJourneyOption.luggage_capacity

small | medium | large | xl

vehicle_meta.fuel_kind

ev_full

vehicle_meta.emission_norm

ev

vehicle_meta.permit_kind

tourist | all_india_tourist | contract_carriage | self_drive_permit | aggregator_permit

EV-with-driver intercity REQUIRES tourist | all_india_tourist | contract_carriage. Self-drive EV REQUIRES self_drive_permit.

vehicle_meta.vehicle_class_certification

commercial_yellow_plate | self_drive_yellow_plate | tourist | private | luxury_charter

ev_specs.battery_chemistry

nmc | lfp | lto | nca | unknown_legacy

ev_specs.charger_kinds_supported[] and preferred/acceptable_charger_kinds

ccs2_fast | ccs2_ultrafast | chademo | type2_ac | gb_t | tesla_supercharger | bharat_dc_001

India consumer EVs primarily use CCS2. Type-2 AC for slow home/destination charging.

charge_stops[].charger_kind

Same enum as charger_kinds_supported.

charge_stops[].amenities_at_stop[]

food_court | washroom | rest_lounge | air_conditioning | covered_parking |
shopping | drinking_water | wifi | mobile_charge | atm | ev_charging_only

charge_stops[].stop_kind

planned_charge | also_food_break | also_washroom | also_rest |
backup_swap_only

fare.charge_cost_borne_by

user | partner | shared

Self-drive EV: typically user. Chauffeur intercity/outstation: typically partner (cost rolled into total). Shared = some pre-charging by partner + user pays mid-trip charges.

start_battery.pct_at_dispatch constraint

Must be ≥ 80 unless explicitly justified in fare_breakdown_text.

vehicle_amenities.child_seat_kind

none | infant | toddler | booster | universal

driver_meta.charge_planning_familiarity

new | familiar_5_to_30_journeys | expert_30_plus_journeys

driver_meta.age_band

21-30 | 31-40 | 41-55 | 56+

user_driving_profile.ev_familiarity_level and rider_qualification_for_user.ev_familiarity_required

none | basic | moderate | expert

rider_qualification_for_user.qualification_failure_reason

none | user_age_below_minimum | license_held_too_short |
ev_familiarity_below_required | license_class_invalid | foreign_license_not_accepted

EvJourneyTrack.status

scheduled | driver_assigned | driver_dispatched | driver_arriving |
arrived_at_pickup | otp_required | trip_started | en_route_leg_1 |
approaching_charge_stop | at_charge_stop_charging | charge_complete |
en_route_leg_n | nearby_destination | reached_destination |
charge_plan_amended | range_anxiety_warning | thermal_warning |
completed | cancelled_by_user | cancelled_by_driver | failed

EvJourneyTrack.location.status

heading_to_pickup | at_pickup | trip_in_progress |
approaching_charger | at_charger_charging | leaving_charger |
nearby_destination | at_destination

cancel_ev_journey.reason

user_changed_mind | weather_block | charger_network_widespread_failure |
vehicle_unavailable | safety_concern | medical_emergency |
no_longer_needed | found_alternative | other

context.trip_purpose

commute_to_work | commute_to_home | leisure | family_visit |
business_trip | medical_visit | religious_pilgrimage | wedding_event |
emergency | other

6. TTBS DIMENSIONS

Per-domain weights (locked; EV override safety to 0.40)

mobility (ev_with_charge_planning): { time: 0.30, taste: 0.10, budget: 0.20, safety: 0.40 }

Safety is the highest of any mobility intent (battery thermal events + charger failure + range anxiety are first-order safety concerns). Taste lower (vehicle is the EV; user preferences narrower).

TIME

SIGNALS USED:
  - eta.total_minutes (drive + charge)                  weight 0.40
  - charge_plan.total_charge_minutes (lower=better)     weight 0.20
  - charge_plan.total_stops (lower=better, within max)  weight 0.15
  - eta.pickup_minutes                                  weight 0.15
  - cancellation.refund_processing_days                 weight 0.10

USER BAND HANDLING:
  - max_charge_stops HARD FILTER
  - max_total_charge_minutes HARD FILTER

TASTE

SIGNALS USED:
  - vehicle.year_of_manufacture                         weight 0.20
  - vehicle.make/model affinity (DNA)                   weight 0.20
  - vehicle_amenities match w/ user prefs               weight 0.20
  - vehicle_amenities.heat_pump                         weight 0.10
  - vehicle_amenities.preconditioning_supported         weight 0.15
  - charge_stops[].amenities_at_stop richness           weight 0.15

HARD FILTERS:
  - ac_required + ac=false → drop
  - ev_min_battery_capacity_kwh > vehicle.battery_capacity_kwh → drop
  - ev_min_real_range_km > vehicle.warm_state_real_range_km → drop

BUDGET

SIGNALS USED:
  - fare.total_inr vs band:
      ok    → ev_hatchback / ev_sedan economy
      good  → ev_sedan / ev_suv
      great → ev_premium / ev_luxury
  - fare.is_upfront_fare=true                           weight 0.20
  - fare.charge_cost_borne_by=partner (no surprise)     weight 0.20
  - fare.total_charge_cost_inr (lower)                  weight 0.15
  - cancellation.free_cancel_until_iso (later=better)   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 valid for journey_kind     HARD FILTER
  - vehicle_meta.permit_states_covered ⊇ states_crossed HARD FILTER
  - vehicle_meta.fitness_certificate_valid_until_iso > destination eta HARD FILTER
  - ev_specs.battery_health_pct >= 80                   HARD FILTER
  - charge_plan.arrival_battery_pct >= preferences.min_arrival_battery_pct HARD FILTER
  - all charge_stops[].charger_compatibility_verified=true HARD FILTER
  - safety_features.fire_extinguisher_lithium_safe       HARD FILTER
  - safety_features.battery_thermal_warning_alerts      weight 0.15
  - safety_features.charger_failure_realtime_alert      weight 0.20
  - safety_features.contingency_tow_to_charger          weight 0.15
  - safety_features.emergency_charger_swap_window_minutes ≤ 30 weight 0.15
  - all charge_stops[].backup_charger_within_5km        weight 0.20
  - all charge_stops[].charger_uptime_30d_pct ≥ 0.95    weight 0.15
  - driver_meta.ev_certification_held (if not self_drive) HARD FILTER
  - driver_meta.charge_planning_familiarity (expert preferred) weight 0.10
  - is_overnight → safety scales 1.5x

HARD FILTERS:
  - female_driver_required → drop male drivers
  - any charge_stop has charger_uptime_30d_pct < 0.85 → drop  (unreliable)
  - any charge_stop has backup_charger_within_5km=false AND charger_uptime_30d_pct < 0.95 → drop

Hidden ranking factor

information_completeness_score weight 0.10.

Charge-plan integrity check

TOMO independently re-validates each charge_stops[].charger_id against the partner's stated charger_uptime_30d_pct via 1% audit (random ping at planned arrival_eta_iso). If mismatch >5%, the partner's partner_charge_plan_success_rate_30d gets adjusted.


7. COMPLETION CONTRACT

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

{
  "intent":            "mobility.book_ev_with_charge_planning",
  "intent_version":    "v1.0.0",
  "external_id":       "BLU-EV-XYZ",
  "amount_inr":         15400,
  "closed_at":         "2026-05-11T15:34:00+05:30",
  "request_id":        "req_evcp_8h3k_...",
  "status":            "completed",
  "journey_ref":       "BLU-EV-XYZ",
  "started_at":        "2026-05-11T06:08:00+05:30",
  "completed_at":      "2026-05-11T15:34:00+05:30",
  "distance_traveled_km": 583.2,
  "drive_minutes_actual": 522,
  "charge_minutes_actual": 56,
  "promised_total_minutes": 540,
  "actual_total_minutes": 578,
  "charge_stops_completed": 1,
  "charge_stops_planned":  1,
  "kwh_added_total":       42.5,
  "charge_cost_actual_inr": 680,
  "charge_cost_borne_by":  "partner",
  "states_traversed":      ["TS", "AP", "KA"],
  "tolls_paid_inr":        1245,
  "battery_pct_at_arrival": 28,
  "any_thermal_warning":   false,
  "any_range_anxiety_event": false,
  "any_charger_failure":   false,
  "currency":          "INR",
  "fare_breakdown_total_inr": 15400,
  "rider_tip_inr":       0,
  "ratings_pending":     true,
  "notes":              ""
}

Status enum: completed | cancelled_by_user | cancelled_by_driver | failed | rerouted_with_extra_charge | partial_completion_battery_failure | charger_chain_failure_partner_compensated


8. WIDGET

WIDGET TYPE:        ev_journey_options
SOURCE:             src/widgets/types.ts
TYPE NAME:          EvJourneyOptionsPayload
RENDERED IN:        components/widgets/EvJourneyOptionsWidget.tsx

Default: 3 stacked rows showing make+model+year, battery_kwh + real_range_km badge, charge plan summary (X stops, Y minutes total), fare with charge_cost_borne_by clarity, key amenities. Tap row → confirmation card with charge-stop timeline (each stop with charger brand, kW, eta, expected charge minutes, backup_charger flag) → "Book". Then EvJourneyTrackingCard with battery strip + charge-session display + range-anxiety indicator.


9. CACHING POLICY

Call TTL Rationale
get_ev_journey_estimates 60s charger availability + charge plan must be fresh
track_ev_journey 0s always live (battery telemetry critical)
book_ev_journey 0s
cancel_ev_journey 0s
update_charge_plan 0s
confirm_charge_at_stop 0s
Failure responses 0s

10. ERROR CODES

Code HTTP Meaning TOMO behavior
NO_VEHICLES_AVAILABLE 503 no EV matches 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
OPTION_EXPIRED 410 option_token / charge_plan_token invalid re-quote
CHARGE_PLAN_INFEASIBLE 400 route too long for vehicle range + max_stops surface
CHARGER_UNAVAILABLE 503 one or more planned chargers down offer revised plan
CHARGER_INCOMPATIBLE 400 vehicle ↔ charger mismatch surface
BATTERY_HEALTH_FAIL 400 partner's vehicle below health floor surface alternate vehicle
BOOKING_NOT_FOUND 404 journey_ref doesn't exist surface
ALREADY_CANCELLED 409 duplicate cancel idempotent return
THERMAL_WARNING_TRIP_HALTED 503 live thermal event forced halt surface emergency response
BACKUP_CHARGER_FAILED 503 primary AND backup down surface tow contingency
FASTAG_INSUFFICIENT 400 balance low top-up CTA
WEATHER_BLOCK 503 route flagged unsafe suggest reschedule

11. SANDBOX → PRODUCTION CHECKLIST

[ ] All §2 inputs validated, request_id echoed
[ ] get_ev_journey_estimates returns ≥3 options for "Hyderabad → Bangalore" with charge plans
[ ] All §4 required fields populated with REAL data
[ ] vehicle_meta + ev_specs truthful + verifiable on demand
[ ] battery_health_pct backed by partner diagnostic logs
[ ] charge_stops[].charger_compatibility_verified actually verified
[ ] charge_stops[].charger_uptime_30d_pct sourced from partner network telemetry
[ ] charge_stops[].backup_charger_within_5km verified via map distance
[ ] Charge-plan-success-rate-30d audited against TOMO 1% sample
[ ] book_ev_journey returns journey_ref + driver assignment within SLA
[ ] track_ev_journey returns battery telemetry ≤5s old
[ ] update_charge_plan triggered on simulated charger failure; new plan within SLA
[ ] confirm_charge_at_stop fires at each completed charge with kWh + cost
[ ] CPC webhook arrives within 60s of journey completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] Trip share URL works with battery strip live
[ ] SOS button + battery thermal alert tested
[ ] Charger network outage simulated; backup charger reroute works
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] All operating-state permits uploaded
[ ] Lithium-safe fire extinguisher verified onboard

12. ANTI-FABRICATION RULES

RULE 1 — No paid placement signals.

RULE 2 — No fake battery_health_pct.
  Must come from partner's diagnostic logs (manufacturer OBD, vehicle BMS).
  TOMO samples 1% journeys and validates against vehicle BMS readout.

RULE 3 — No fake warm_state_real_range_km.
  Range claims must be backed by partner's own real-world telematics across
  the user's expected speed + temperature range. Stating range under WLTP
  ideal conditions when reality is 70% = breach.

RULE 4 — No fake charger_uptime_30d_pct.
  Uptime stats must come from partner's charger network telemetry. TOMO
  pings each charger_id at planned arrival_eta_iso. Mismatch >5% = breach.

RULE 5 — No fake charge_plan_success_rate_30d.

RULE 6 — Charger compatibility cannot be fudged.
  charger_compatibility_verified=true requires partner-confirmed plug type
  match. Fudging CCS2 vs Type-2 = severe safety breach.

RULE 7 — Vehicle plate must match dispatched vehicle.

RULE 8 — Fare displayed must be honored.
  is_upfront_fare=true means fare_locked_until_iso. Charge cost is the
  ONLY field that may shift if charger_failure_realtime forces a
  more-expensive backup, AND user must be notified before extra-charge
  charging begins.

RULE 9 — Driver KYC + EV certification claims must be verifiable.

RULE 10 — Fatigue compliance is non-negotiable (driver journeys).

RULE 11 — No hidden charger network outage.
  If partner becomes aware of charger network issue post-booking but before
  pickup, partner MUST notify user + offer revised plan or full refund.
  Silent ride into a known-outage charger = severe breach.

RULE 12 — No surge gaming on charge cost.
  Charge cost lines must reflect actual partner contract rates with the
  charger network. Inflating charge cost > 110% of network public rate = breach.

RULE 13 — Backup charger is real, not aspirational.
  backup_charger_within_5km=true means an alternate charger has been
  identified by lat/lng. Stating true with no backup_charger_id = breach.

RULE 14 — Battery thermal warnings are escalated, not suppressed.
  battery_thermal_warning_active=true MUST trigger user notification +
  partner safety dispatch. Hiding thermal events to avoid trip cancellation
  cost = severe safety breach.

RULE 15 — Range anxiety warnings are honest.
  range_anxiety_warning_active=true when predicted_pct_at_destination falls
  below preferences.min_arrival_battery_pct. Suppressing this warning to
  keep user committed to trip = safety breach.

RULE 16 — No commission-based response shaping.

RULE 17 — Cancel charges must match displayed thresholds.

VERSION HISTORY

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