food.book_dine_in — Full Intent Specification
INTENT NAMESPACE: food
INTENT NAME: book_dine_in
FULL ID: food.book_dine_in
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-10
TTBS WEIGHTS: time 0.20 · taste 0.40 · budget 0.20 · safety 0.20
Dine-in is restaurant table reservation — different shape from delivery in five locked ways: (a) table + slot are the listing unit, not dish + rider; (b) cover charge / deposit / table_kind replace delivery_fee; (c) meal_period + duration_minutes define the booking window; (d) accessibility + dietary at the dish level become accessibility + dietary at the seating level (private dining, allergen-protected kitchen); (e) safety stays meaningful (food handling) but adds physical-safety concerns absent in delivery (well-lit access, female-friendly hours).
1. NATURAL LANGUAGE COVERAGE
Classifies IN
- "table for 4 at Paradise tonight"
- "book a table at Olive Beach for 8pm"
- "reservation at Farzi Cafe Saturday"
- "dinner reservation for 2 at 7:30pm"
- "table for date night Friday"
- "lunch at Indian Accent tomorrow"
- "I want to dine in at Bombay Brasserie"
- "book a private dining room for 8 people"
- "reservation for 6 at Paradise biryani 8:30pm"
Classifies OUT — borderline NO
- "biryani for dinner" →
food.order_delivery - "tiffin subscription" →
food.subscribe_tiffin - "chef at home for a dinner party" →
food.book_chef_at_home - "table at Paradise with 30% off offer" →
food.book_dine_in_with_offer - "catering for a wedding" →
food.book_catering_event
MULTI-INTENT TRIGGERS
- "book Olive Beach for 8 and a cab" →
food.book_dine_in+mobility.book_intracity_ride - "table at Indian Accent and book a hotel nearby" →
food.book_dine_in+travel.book_hotel - "reservation at Paradise with anniversary cake" →
food.book_dine_in+food.order_cake_or_special
2. INPUT — TOMO → PROVIDER
{
"intent": "food.book_dine_in",
"intent_version": "v1.0.0",
"request_id": "req_dn_8h2k_2026-05-10T18:00:00Z",
"user_session_id": "anon_user_token_or_uid",
"search_area": {
"lat": 17.4435,
"lng": 78.3772,
"radius_km": 5,
"city": "Hyderabad",
"state_code": "TS",
"country_code": "IN"
},
"scheduled_for_iso": "2026-05-10T20:30:00+05:30",
"duration_minutes": 90,
"meal_period": "dinner",
"party": {
"adult_count": 3,
"child_count": 1,
"infant_count": 0,
"high_chair_required": true,
"wheelchair_required": false,
"occasion": "birthday",
"dietary_filters": ["veg"],
"allergens_to_avoid": ["peanuts"]
},
"preferences": {
"cuisines_wanted": ["hyderabadi", "south_indian", "north_indian"],
"budget_band": "good",
"budget_max_inr_per_head": 800,
"preferred_seating_kind": ["indoor_ac", "outdoor_garden", "private_dining"],
"atmosphere_kinds_wanted": ["family_friendly", "romantic", "quiet"],
"spice_level_max": "medium",
"no_onion_no_garlic": false,
"jain_meal_required": false,
"halal_required": false,
"alcohol_served_acceptable": true,
"music_kind_acceptable": ["soft_instrumental", "lounge", "no_music"],
"valet_parking_required": false,
"kids_menu_required": true
},
"context": {
"user_locale": "en-IN",
"user_currency_pref": "INR",
"is_weekend": false,
"is_festival_day": false,
"weather_celsius": 29,
"rain_probability_pct": 10,
"trust_signals": {
"is_repeat_customer": true,
"prior_dine_in_with_partner": 2,
"user_account_age_days": 312,
"verified_phone": true
}
}
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, equals "food.book_dine_in" |
|
search_area.radius_km |
int | REQUIRED, 1-25 | |
scheduled_for_iso |
ISO_DATETIME | REQUIRED | |
duration_minutes |
int | REQUIRED, 30-300 | typical 90-180 |
meal_period |
enum | REQUIRED, see §5 | |
party.adult_count |
int | REQUIRED, ≥1 | |
party.child_count |
int | REQUIRED, ≥0 | |
party.infant_count |
int | REQUIRED, ≥0 | |
party.high_chair_required |
bool | REQUIRED | |
party.wheelchair_required |
bool | REQUIRED | |
party.occasion |
enum | REQUIRED, see §5 | |
preferences.preferred_seating_kind |
array |
REQUIRED, ≥1 | see §5 |
preferences.atmosphere_kinds_wanted |
array |
REQUIRED, ≥1 | see §5 |
preferences.alcohol_served_acceptable |
bool | REQUIRED | drives bar-restaurant filter |
preferences.music_kind_acceptable |
array |
REQUIRED, ≥1 | see §5 |
preferences.valet_parking_required |
bool | REQUIRED | |
preferences.kids_menu_required |
bool | REQUIRED | drives child-friendly filter |
context.is_weekend |
bool | REQUIRED | |
context.is_festival_day |
bool | REQUIRED | drives demand model |
Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.
3. PROVIDER TOOLS
Tool 1: search_dine_in_options
PURPOSE: return ranked list of restaurants with available slots
INPUT: §2 request body
OUTPUT: { results: DineInOption[], result_token, expires_at }
SLA: p50 < 600ms, p95 < 1500ms
RATE LIMIT: ≤ 1/sec per user
Tool 2: get_restaurant_detail
PURPOSE: full detail (menu preview, photos, reviews, slots)
INPUT: { restaurant_id, request_id, user_session_id }
OUTPUT: RestaurantDetail (§4)
SLA: p95 < 800ms
Tool 3: get_available_slots
PURPOSE: live slot availability for a specific restaurant + date
INPUT: { restaurant_id, date_iso, party_size, request_id }
OUTPUT: { slots: SlotOption[], expires_at }
SLA: p95 < 500ms
Tool 4: book_table
PURPOSE: commit reservation
INPUT: { restaurant_id, slot_id, party, payment_token, request_id, idempotency_key, user_phone, special_requests }
OUTPUT: { reservation_ref, status, slot_iso, table_assigned, deposit_inr, cancellation_window_iso }
SLA: p95 < 4000ms
IDEMPOTENCY: REQUIRED on idempotency_key
Tool 5: modify_reservation
PURPOSE: modify time / party size / special requests
INPUT: { reservation_ref, new_slot_iso, new_party_size, new_special_requests, request_id }
OUTPUT: { revised_status, revised_table_assigned, deposit_delta_inr }
SLA: p95 < 2000ms
Tool 6: cancel_reservation
PURPOSE: cancel
INPUT: { reservation_ref, reason, request_id }
OUTPUT: { status, refund_amount_inr, no_show_charge_inr, refund_processing_days }
SLA: p95 < 2000ms
Tool 7: confirm_arrival
PURPOSE: partner marks user arrived (or no-show)
INPUT: { reservation_ref, status, observed_iso, request_id }
OUTPUT: { acknowledged: true }
SLA: p95 < 800ms
Tool 8: rate_dine_in
PURPOSE: post-meal rating + tip
INPUT: { reservation_ref, rating_5star, food_score, ambience_score, service_score, comment, tip_inr, request_id }
OUTPUT: { acknowledged: true }
SLA: p95 < 800ms
All eight REQUIRED.
4. RESPONSE SHAPE
DineInOption (returned by search_dine_in_options)
restaurant: Restaurant, REQUIRED
available_slots: array<SlotOption>, REQUIRED, ≥1
match_reason: STRICT ENUM, REQUIRED
distance_from_user_km: float, REQUIRED
avg_check_inr_per_head: INR_INTEGER, REQUIRED
sample_dishes: array<DishSummary>, REQUIRED, ≥3, ≤6 # menu preview
Restaurant
id: string, REQUIRED
merchant_id: string, REQUIRED
name: string, REQUIRED
official_name: string, REQUIRED
brand: string, REQUIRED
kind: STRICT ENUM, REQUIRED
sub_kind: STRICT ENUM, REQUIRED
cuisines: array<enum>, REQUIRED, ≥1
specialties: array<string>, REQUIRED, ≥0
veg_only_kitchen: boolean, REQUIRED
jain_meals_available: boolean, REQUIRED
halal_meals_available: boolean, REQUIRED
alcohol_served: boolean, REQUIRED
alcohol_license_kind: STRICT ENUM, REQUIRED
vegan_options_count: int, REQUIRED, ≥0
gluten_free_options_count: int, REQUIRED, ≥0
total_dish_count: int, REQUIRED, ≥1
address:
line_1: string, REQUIRED
line_2: string, REQUIRED
neighborhood: string, REQUIRED
city: string, REQUIRED
state: string, REQUIRED
pincode: string, REQUIRED
country_code: string, REQUIRED
lat: float, REQUIRED
lng: float, REQUIRED
google_place_id: string, REQUIRED
landmark: string, REQUIRED
distance_from_user_km: float, REQUIRED
ratings:
overall_score: float, REQUIRED, 0-5
overall_count: int, REQUIRED, ≥0
recent_30day_score: float, REQUIRED, 0-5
recent_30day_count: int, REQUIRED, ≥0
food_quality_score: float, REQUIRED, 0-5
ambience_score: float, REQUIRED, 0-5
service_score: float, REQUIRED, 0-5
hygiene_score: float, REQUIRED, 0-5
value_for_money_score: float, REQUIRED, 0-5
category_breakdown: object, REQUIRED
taste: float, REQUIRED, 0-5
portion: float, REQUIRED, 0-5
accuracy: float, REQUIRED, 0-5
presentation: float, REQUIRED, 0-5
operating_hours:
is_open_now: boolean, REQUIRED
next_open_iso: ISO_DATETIME, REQUIRED
next_close_iso: ISO_DATETIME, REQUIRED
hours_of_operation: array, REQUIRED, 7 entries
- day_of_week: STRICT ENUM, REQUIRED
open_iso_time: string, REQUIRED
close_iso_time: string, REQUIRED
closed_today: boolean, REQUIRED
meal_periods_supported: array<STRICT ENUM>, REQUIRED, may be empty
seating:
total_capacity: int, REQUIRED, ≥1
indoor_ac_seats: int, REQUIRED, ≥0
indoor_non_ac_seats: int, REQUIRED, ≥0
outdoor_garden_seats: int, REQUIRED, ≥0
outdoor_terrace_seats: int, REQUIRED, ≥0
private_dining_rooms: int, REQUIRED, ≥0
private_dining_max_capacity: int, REQUIRED, ≥0
bar_seats: int, REQUIRED, ≥0
booth_seats: int, REQUIRED, ≥0
rooftop_seats: int, REQUIRED, ≥0
high_chair_count: int, REQUIRED, ≥0
wheelchair_accessible: boolean, REQUIRED
wheelchair_table_count: int, REQUIRED, ≥0
atmosphere:
noise_level: STRICT ENUM, REQUIRED
lighting: STRICT ENUM, REQUIRED
music_kind: STRICT ENUM, REQUIRED
music_volume: STRICT ENUM, REQUIRED
family_friendly: boolean, REQUIRED
romantic_friendly: boolean, REQUIRED
business_friendly: boolean, REQUIRED
pet_friendly: boolean, REQUIRED
kid_friendly: boolean, REQUIRED
has_kids_menu: boolean, REQUIRED
has_kids_play_area: boolean, REQUIRED
smoking_zone_available: boolean, REQUIRED
smoking_outdoor_only: boolean, REQUIRED
amenities:
wifi_available: boolean, REQUIRED
wifi_free: boolean, REQUIRED
parking_kind: STRICT ENUM, REQUIRED
valet_available: boolean, REQUIRED
valet_charge_inr: INR_INTEGER, REQUIRED
ev_charging_available: boolean, REQUIRED
air_conditioning: boolean, REQUIRED
power_backup: boolean, REQUIRED
trust:
fssai_license_number: string, REQUIRED
fssai_license_valid_until: ISO_DATE, REQUIRED
fssai_grade: STRICT ENUM, REQUIRED
cleanliness_audit_iso: ISO_DATETIME, REQUIRED
cleanliness_audit_score: int, REQUIRED, 0-100
partner_account_age_days: int, REQUIRED, ≥0
tomo_field_team_audited: boolean, REQUIRED
health_inspection_authority: STRICT ENUM, REQUIRED
food_handler_kyc_pct: int, REQUIRED, 0-100
alcohol_license_valid_until: ISO_DATE, REQUIRED # if alcohol_served=false, may be sentinel
fire_safety_compliant: boolean, REQUIRED
cctv_in_dining_area: boolean, REQUIRED
female_friendly_certified: boolean, REQUIRED # partner-internal cert
has_panic_button: boolean, REQUIRED
photos:
thumbnail_url: URL, REQUIRED
hero_url: URL, REQUIRED
ambience_photos_url: URL, REQUIRED # JSON manifest of multiple photos
menu_photos_url: URL, REQUIRED
exterior_photos_url: URL, REQUIRED
food_photos_url: URL, REQUIRED
ai_generated_photos: boolean, REQUIRED # MUST be false
freshness:
data_last_synced_iso: ISO_DATETIME, REQUIRED
menu_last_updated_iso: ISO_DATETIME, REQUIRED
prices_last_updated_iso: ISO_DATETIME, REQUIRED
last_inspected_iso: ISO_DATETIME, REQUIRED
_provider:
name: string, REQUIRED
tomo_partner_id: string, REQUIRED
partner_tier: STRICT ENUM, REQUIRED
deep_link: URL, REQUIRED
partner_restaurant_url: URL, REQUIRED
customer_support_phone: string, REQUIRED
customer_support_email: string, REQUIRED
customer_support_24x7: boolean, REQUIRED
in_app_chat_supported: boolean, REQUIRED
partner_dine_in_volume_30d: int, REQUIRED, ≥0
partner_no_show_rate_30d: float, REQUIRED, 0-1
SlotOption
slot_id: string, REQUIRED
slot_iso: ISO_DATETIME, REQUIRED
duration_minutes: int, REQUIRED
seating_kind: STRICT ENUM, REQUIRED # see §5
table_kind: STRICT ENUM, REQUIRED # 2_seater | 4_seater | 6_seater | 8_seater | banquet | private_room
covers_max: int, REQUIRED, ≥1
covers_min: int, REQUIRED, ≥0
deposit_inr: INR_INTEGER, REQUIRED # 0 if no deposit required
deposit_redeemable_against_meal: boolean, REQUIRED
cover_charge_inr: INR_INTEGER, REQUIRED # entry fee, applied even if no order; 0 typical
arrival_window_minutes: int, REQUIRED # how late before table released
cancellation_until_iso: ISO_DATETIME, REQUIRED
cancellation_charge_after_iso_inr: INR_INTEGER, REQUIRED
no_show_charge_inr: INR_INTEGER, REQUIRED
buffet_or_a_la_carte: STRICT ENUM, REQUIRED # buffet | a_la_carte | both
buffet_price_per_head_inr: INR_INTEGER, REQUIRED # 0 if not buffet
slot_kind: STRICT ENUM, REQUIRED # see §5
high_chair_available: boolean, REQUIRED
wheelchair_accessible_table: boolean, REQUIRED
near_window: boolean, REQUIRED
near_kitchen: boolean, REQUIRED
view_kind: STRICT ENUM, REQUIRED # see §5
freshness_iso: ISO_DATETIME, REQUIRED
DishSummary (sample dishes for menu preview)
id: string, REQUIRED
name: string, REQUIRED
description: string, REQUIRED
price_inr: INR_INTEGER, REQUIRED
mrp_inr: INR_INTEGER, REQUIRED
photo_url: URL, REQUIRED
photo_authenticity_verified: boolean, REQUIRED
photo_ai_generated: boolean, REQUIRED # MUST be false
veg_or_non_veg: STRICT ENUM, REQUIRED
spice_level: STRICT ENUM, REQUIRED
allergens_present: array<enum>, REQUIRED
dietary_tags: array<enum>, REQUIRED
serves_count: int, REQUIRED, ≥1
calories_kcal: int, REQUIRED
oil_used: STRICT ENUM, REQUIRED
popularity_rank: int, REQUIRED
order_count_30day: int, REQUIRED, ≥0
average_dish_rating: float, REQUIRED, 0-5
recommended: boolean, REQUIRED
RestaurantDetail (returned by get_restaurant_detail)
Superset of Restaurant with full menu (sections + dishes), expanded reviews, all photos, and full slot availability for the next 7 days.
restaurant: Restaurant, REQUIRED
menu_sections: array<MenuSection>, REQUIRED, ≥1
slots_next_7_days: array<SlotOption>, REQUIRED, ≥0
reviews: array, REQUIRED, ≥0
- excerpt: string, REQUIRED
score: float, REQUIRED, 0-5
food_score: float, REQUIRED, 0-5
ambience_score: float, REQUIRED, 0-5
service_score: float, REQUIRED, 0-5
visit_kind: STRICT ENUM, REQUIRED
review_date: ISO_DATE, REQUIRED
verified_visit: boolean, REQUIRED
specialties_signature_dishes: array<dish_id>, REQUIRED, ≥0
Reservation (returned by book_table)
reservation_ref: string, REQUIRED
status: STRICT ENUM, REQUIRED # see §5
slot_iso: ISO_DATETIME, REQUIRED
duration_minutes: int, REQUIRED
table_assigned: string, REQUIRED # "Table 14, indoor AC"
restaurant_address: string, REQUIRED
restaurant_phone: string, REQUIRED
deposit_paid_inr: INR_INTEGER, REQUIRED
arrival_window_close_iso: ISO_DATETIME, REQUIRED
cancellation_until_iso: ISO_DATETIME, REQUIRED
qr_code_for_arrival: URL, REQUIRED
support_phone: string, REQUIRED
support_email: string, REQUIRED
Forbidden fields
paid_placement_score | sponsored_rank | promotion_priority |
artificial_demand_text | fake_recent_reservation_text |
auto_inflate_rating | partner_paid_for_top_listing |
ai_generated_photos (must equal false) | hidden_cover_charge_inr |
fake_partner_no_show_rate_30d
5. CONTROLLED VOCABULARIES
Restaurant.kind
restaurant | bistro | cafe | bakery_cafe | bar | pub | rooftop_bar |
fine_dining | family_restaurant | qsr | dessert_parlor | hotel_restaurant
Restaurant.sub_kind
fine_dining | casual_dining | family_restaurant | fast_casual | quick_service |
buffet | a_la_carte | thali_house | meals_house | brewery | wine_bar |
sports_bar | rooftop | poolside | lounge_bar
cuisines
hyderabadi | south_indian | north_indian | bengali | punjabi | gujarati |
maharashtrian | rajasthani | kerala | tamilian | andhra | konkani | goan |
chinese | thai | korean | japanese | sushi | italian | french | continental |
mediterranean | mexican | lebanese | turkish | greek | mughlai | awadhi |
kashmiri | jain | vegan | live_grill | bbq | tandoor | chaat | street_food |
fusion | bowl | salad_bar | dessert | bakery | breakfast | brunch
meal_period
breakfast | brunch | lunch | tea_time | snacks | dinner | late_night | open_all_day
party.occasion
casual | date_night | anniversary | birthday | family_dinner |
friends_meetup | business_meeting | client_dinner | celebration |
proposal | engagement | reunion | farewell | other
dietary_filters
veg | non_veg | egg | vegan | jain | halal | kosher |
gluten_free | dairy_free | sugar_free | low_carb | low_sodium |
keto | paleo | high_protein | low_calorie | satvik
allergens_to_avoid
peanuts | tree_nuts | dairy | eggs | wheat | gluten | soy |
fish | shellfish | sesame | mustard | celery | lupin | sulphites
preferences.preferred_seating_kind and SlotOption.seating_kind
indoor_ac | indoor_non_ac | outdoor_garden | outdoor_terrace |
private_dining | bar_seating | booth | rooftop | poolside | window_seat |
chef_table | counter_seating
preferences.atmosphere_kinds_wanted
family_friendly | romantic | business | quiet | lively | rooftop_view |
poolside | garden | live_music | dj | sports_screen | pet_friendly |
kid_play_area | accessible
preferences.music_kind_acceptable and Restaurant.atmosphere.music_kind
no_music | soft_instrumental | lounge | jazz | classical | bollywood |
indie | live_band | dj | edm | hip_hop | acoustic | regional
Restaurant.atmosphere.noise_level
quiet | moderate | lively | loud
Restaurant.atmosphere.lighting
bright | warm | dim | candlelight | mixed
Restaurant.atmosphere.music_volume
none | low | moderate | high
Restaurant.amenities.parking_kind
valet_only | self_park_lot | street_parking | mall_parking |
no_parking | basement | rooftop_parking
Restaurant.alcohol_license_kind
none | bar_l_19 | restaurant_l_3 | wine_l_24 | beer_only | full_bar
SlotOption.seating_kind
Same enum as preferred_seating_kind.
SlotOption.table_kind
2_seater | 4_seater | 6_seater | 8_seater | banquet | private_room |
chef_table | rooftop_couch | window_table
SlotOption.buffet_or_a_la_carte
buffet | a_la_carte | both | tasting_menu | chef_special_only
SlotOption.slot_kind
walk_in_compatible | reserved_only | premium_slot | early_bird_slot |
late_dinner_slot | weekend_premium | event_special
SlotOption.view_kind
none | city | garden | pool | beach | mountain | sunset | sunrise |
courtyard | atrium | none_indoor
Reservation.status
confirmed | pending_partner_acceptance | pending_payment |
arrival_window_active | seated | meal_in_progress | completed |
cancelled_by_user | cancelled_by_restaurant | no_show | failed
Restaurant.trust.fssai_grade
A | B | C | unrated
Restaurant.trust.health_inspection_authority
fssai | local_municipality | none
RestaurantDetail.reviews[].visit_kind
date_night | family | friends | business | solo | celebration | other
dish.veg_or_non_veg
veg | non_veg | egg | vegan | jain
dish.spice_level
mild | medium | spicy | very_spicy
dish.oil_used
sunflower | mustard | groundnut | rice_bran | olive | coconut | ghee | butter | palm | mixed | none
cancel_reservation.reason
user_changed_mind | wrong_time | wrong_party_size | found_alternative |
medical_emergency | weather | partner_canceled_first | other
merchant_id resolution order
1. Google Place ID
2. FSSAI license number
3. partner_id + ":" + restaurant_id
6. TTBS DIMENSIONS
Per-domain weights (locked; dine-in override)
food (book_dine_in): { time: 0.20, taste: 0.40, budget: 0.20, safety: 0.20 }
Time drops (slot is scheduled, not ASAP). Taste rises (the experience IS the meal). Safety stays meaningful (food handling + physical).
TIME
SIGNALS USED:
- slot_iso match request HARD FILTER (within ±30 min default)
- distance_from_user_km weight 0.30
- operating_hours.is_open_now HARD FILTER
- SlotOption.arrival_window_minutes (longer=better) weight 0.20
- eta to reach (driving) ≤ time_until_slot HARD FILTER
USER BAND HANDLING:
- "anytime tonight" → relax slot match window
- "exactly 8pm" → tighten match
TASTE
SIGNALS USED:
- ratings.food_quality_score weight 0.20
- ratings.ambience_score weight 0.20
- ratings.recent_30day_score weight 0.15
- cuisines match user request weight 0.20
- atmosphere.match (family_friendly, romantic etc) weight 0.15
- SlotOption.view_kind quality weight 0.10
HARD FILTERS:
- dietary_filters / allergens
- jain_meal_required, halal_required
- alcohol_served_acceptable=false → drop alcohol-only bars
- kids_menu_required AND has_kids_menu=false → drop
BUDGET
SIGNALS USED:
- avg_check_inr_per_head vs band:
ok → 0–33rd percentile (cuisine, city)
good → 33rd–66th
great → 66th+
- SlotOption.deposit_inr (lower=better, all else equal) weight 0.20
- SlotOption.cover_charge_inr (lower=better) weight 0.20
- amenities.valet_charge_inr (if valet required) weight 0.15
HARD FILTERS:
- avg_check > preferences.budget_max_inr_per_head → drop
SAFETY
SIGNALS USED:
- trust.fssai_grade (A=high) weight 0.25
- trust.cleanliness_audit_score weight 0.20
- trust.fire_safety_compliant HARD FILTER
- trust.alcohol_license_valid_until > slot_iso (if alcohol_served) HARD FILTER
- trust.cctv_in_dining_area weight 0.10
- trust.female_friendly_certified
(for late dinner, female-led party) weight 0.15
- trust.has_panic_button weight 0.10
- trust.tomo_field_team_audited weight 0.10
- allergens overlap on dish level → drop dish (handled in Restaurant aggregation)
- is_late_night_slot → safety scales 1.3x
HARD FILTERS:
- jain_meal_required
- halal_required
- wheelchair_required → drop non-accessible
Hidden ranking factor
information_completeness_score weight 0.10.
7. COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
X-TOMO-Timestamp: <ms>
X-TOMO-Signature: sha256=<hex>
{
"intent": "food.book_dine_in",
"intent_version": "v1.0.0",
"external_id": "ZOMATO-RES-XYZ",
"amount_inr": 3850,
"closed_at": "2026-05-10T22:14:00+05:30",
"request_id": "req_dn_8h2k_...",
"status": "completed",
"reservation_ref": "ZOMATO-RES-XYZ",
"merchant_id": "ChIJxxxxx",
"restaurant_id": "zomato_rest_8423",
"seated_at": "2026-05-10T20:32:00+05:30",
"departed_at": "2026-05-10T22:08:00+05:30",
"promised_slot_iso": "2026-05-10T20:30:00+05:30",
"actual_seat_iso": "2026-05-10T20:32:00+05:30",
"covers_seated": 4,
"deposit_redeemed_inr": 500,
"no_show_charge_inr": 0,
"currency": "INR",
"fare_breakdown_total_inr": 3850,
"rider_tip_inr": 0,
"ratings_pending": true,
"notes": ""
}
Status enum: completed | cancelled_by_user | cancelled_by_restaurant | no_show | failed | partial_completion_user_left_early
8. WIDGET
WIDGET TYPE: dine_in_options
SOURCE: src/widgets/types.ts
TYPE NAME: DineInOptionsPayload
RENDERED IN: components/widgets/DineInOptionsWidget.tsx
Default: 3 stacked rows showing restaurant name, cuisine, slot pill, avg-check-per-head, atmosphere badges. Tap row → restaurant detail card with menu preview, photos, slot grid, reviews, atmosphere/amenities → "Reserve". Then ReservationCard with QR code + arrival window + directions.
9. CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
search_dine_in_options |
60s | slot availability shifts |
get_restaurant_detail |
5min | menu rarely changes |
get_available_slots |
30s | live availability |
book_table |
0s | |
modify_reservation |
0s | |
cancel_reservation |
0s | |
confirm_arrival |
0s | |
| Failure responses | 0s |
10. ERROR CODES
| Code | HTTP | Meaning | TOMO behavior |
|---|---|---|---|
NO_SLOTS_AVAILABLE |
503 | no slots match | suggest alternates |
RESTAURANT_CLOSED |
409 | restaurant closed for slot | drop, refresh |
OUT_OF_SERVICE_AREA |
400 | outside coverage | surface |
OPTION_EXPIRED |
410 | slot_id invalid | re-quote |
SLOT_JUST_TAKEN |
409 | slot booked by another user | re-quote |
MINIMUM_PARTY_SIZE |
400 | party below min | surface |
OVER_CAPACITY |
400 | party exceeds slot capacity | surface alternate |
DEPOSIT_REQUIRED |
402 | deposit not paid | surface |
ALCOHOL_LICENSE_EXPIRED |
503 | for alcohol restaurants | surface |
RESERVATION_NOT_FOUND |
404 | reservation_ref doesn't exist | surface |
ALREADY_CANCELLED |
409 | duplicate cancel | idempotent return |
11. SANDBOX → PRODUCTION CHECKLIST
[ ] All §2 inputs validated, request_id echoed
[ ] search_dine_in_options returns ≥10 restaurants with available slots
[ ] All §4 fields populated with REAL data
[ ] FSSAI license + grade present on every restaurant
[ ] alcohol_license valid for alcohol-serving establishments
[ ] photo_ai_generated == false everywhere
[ ] Allergens_present complete
[ ] Calorie macros on dishes per universal rule
[ ] book_table returns valid reservation_ref within SLA
[ ] modify_reservation handles slot + party changes correctly
[ ] cancel respects cancellation_until_iso
[ ] confirm_arrival fires within 5min of seat or no_show
[ ] CPC webhook within 60s of completion
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] No paid placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO field call
[ ] Fire safety + cleanliness audits uploaded
[ ] Female-friendly certification verified (if claimed)
[ ] Wheelchair accessibility tested in person
12. ANTI-FABRICATION RULES
RULE 1 — No paid placement signals.
RULE 2 — No artificial scarcity.
"Only 1 slot left" requires real slot count. TOMO samples.
RULE 3 — Ratings unrounded floats from verified visits.
RULE 4 — No AI-generated photos. ai_generated_photos MUST be false.
RULE 5 — Deposit must be redeemable as advertised.
deposit_redeemable_against_meal=true means user's bill is reduced by
deposit_paid_inr. Charging full bill + keeping deposit = breach.
RULE 6 — No-show charges must match displayed.
no_show_charge_inr cannot be inflated post-booking.
RULE 7 — Alcohol license claims verifiable.
alcohol_served=true with expired license = severe compliance breach.
RULE 8 — FSSAI grade honest.
Self-reporting A when actual is B = breach.
RULE 9 — No commission-based response shaping.
RULE 10 — Female-friendly certification real.
female_friendly_certified=true requires partner-internal documented program.
TOMO ops field-tests by sending female test ops at random.
RULE 11 — Allergens_present must be complete.
Missing an allergen that turns out to be present = compliance breach.
RULE 12 — Slot honored or compensated.
Promised slot must be honored within arrival_window_minutes. If restaurant
cannot seat, partner pays driver_cancel_compensation equivalent.
RULE 13 — Capacity claims real.
total_capacity must match physical reality. Inflating to attract
larger-party bookings then refusing = breach.
VERSION HISTORY
v1.0.0 — 2026-05-10 — Initial spec