food.subscribe_tiffin — Full Intent Specification
INTENT NAMESPACE: food
INTENT NAME: subscribe_tiffin
FULL ID: food.subscribe_tiffin
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-10
TTBS WEIGHTS: time 0.20 · taste 0.40 · budget 0.30 · safety 0.10
Tiffin subscription is recurring meal delivery (1-3 meals/day, fixed window, billed weekly/monthly). It differs from per-order delivery in five locked ways: (a) recurrence block defines the schedule; (b) meal_plan is a rotating menu, not a single dish; (c) billing_period aggregates many meals; (d) pause/resume + skip-day are first-class; (e) safety stays at 0.10 (vetted partner over time) but allergen/dietary HARD FILTERS still apply. Closest cousin: mobility.book_recurring_commute. Per-meal CPC + closure CPC like recurring_commute.
1. NATURAL LANGUAGE COVERAGE
Classifies IN
- "subscribe to lunch tiffin for the month"
- "tiffin service near me"
- "daily home-style meals to office"
- "monthly tiffin Madhapur"
- "veg tiffin subscription Mon-Fri"
- "Andhra meals home delivery subscription"
- "weekly dabba service for me and roommate"
- "Jain tiffin subscription"
- "two tiffin per day breakfast and lunch"
Classifies OUT — borderline NO
- "biryani for dinner today" →
food.order_delivery - "table for 4 at Paradise" →
food.book_dine_in - "chef at home for the week" →
food.book_chef_at_home - "groceries for the month" →
grocery.subscribe_grocery(separate domain)
MULTI-INTENT TRIGGERS
- "tiffin subscription and weekly grocery" →
food.subscribe_tiffin+grocery.order_delivery - "lunch tiffin and daily commute cab" →
food.subscribe_tiffin+mobility.book_recurring_commute - "tiffin subscription and KYC verify" →
food.subscribe_tiffin+compliance.verify_kyc
2. INPUT — TOMO → PROVIDER
{
"intent": "food.subscribe_tiffin",
"intent_version": "v1.0.0",
"request_id": "req_tif_3k9p_2026-05-10T08:00:00Z",
"user_session_id": "anon_user_token_or_uid",
"subscription_kind": "monthly_lunch_only",
"delivery_address": {
"lat": 17.4504,
"lng": 78.3811,
"line_1": "Flat 502, SriHomes Apartment",
"line_2": "Hitech City Main Road",
"neighborhood": "Madhapur",
"city": "Hyderabad",
"state": "Telangana",
"pincode": "500081",
"country_code": "IN",
"delivery_notes": "Gate code 4521, leave at door",
"place_kind": "office"
},
"recurrence": {
"pattern": "mon_to_sat",
"meals_per_day": "lunch_only",
"lunch_delivery_window": {
"start_iso_local": "12:30:00",
"end_iso_local": "13:30:00"
},
"breakfast_delivery_window": null,
"dinner_delivery_window": null,
"skip_dates": ["2026-05-15", "2026-05-22"],
"active_from_iso": "2026-05-12",
"active_until_iso": "2026-06-12"
},
"billing": {
"period_kind": "monthly",
"auto_renew": true,
"billing_day_of_month": 10
},
"diners": {
"diner_count": 1,
"diner_breakdown": {"adults": 1, "children": 0, "infants": 0},
"dietary_filters": ["veg", "no_onion_no_garlic"],
"allergens_to_avoid": ["peanuts"],
"preferences_text_hint": "low spice, more variety in vegetables"
},
"preferences": {
"cuisine_preferred": "andhra",
"cuisine_acceptable": ["andhra", "south_indian", "north_indian"],
"spice_level_max": "medium",
"regional_authenticity_required": true,
"menu_rotation_minimum_days": 14,
"tiffin_packaging": "stainless_steel_dabba",
"delivery_kind_preferred": "home_delivery",
"budget_band": "good",
"budget_max_inr_per_period": 4500,
"max_eta_minutes": 15,
"kitchen_visit_friendly": true,
"delivery_personnel_kyc_required": true
},
"context": {
"user_locale": "en-IN",
"user_currency_pref": "INR",
"trip_purpose": "office_lunch",
"trust_signals": {
"is_repeat_customer": false,
"prior_subscriptions_with_partner": 0,
"user_account_age_days": 312,
"verified_address": true,
"verified_phone": true
}
}
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, equals "food.subscribe_tiffin" |
|
subscription_kind |
enum | REQUIRED, see §5 | |
delivery_address.place_kind |
enum | REQUIRED | |
recurrence.pattern |
enum | REQUIRED, see §5 | |
recurrence.meals_per_day |
enum | REQUIRED, STRICT breakfast_only | lunch_only | dinner_only | breakfast_lunch | breakfast_dinner | lunch_dinner | three_meals |
|
recurrence.lunch_delivery_window |
object | REQUIRED, may be null | required if meals_per_day includes lunch |
recurrence.skip_dates |
array |
REQUIRED, may be empty | |
recurrence.active_from_iso |
ISO_DATE | REQUIRED | |
recurrence.active_until_iso |
ISO_DATE | REQUIRED | |
billing.period_kind |
enum | REQUIRED, STRICT weekly | monthly | quarterly |
|
billing.auto_renew |
bool | REQUIRED | |
billing.billing_day_of_month |
int | REQUIRED, 1-31 | |
diners.diner_count |
int | REQUIRED, ≥1 | |
diners.diner_breakdown |
object | REQUIRED | adults + children + infants |
diners.dietary_filters |
array |
REQUIRED, may be empty | see §5 |
diners.allergens_to_avoid |
array |
REQUIRED, may be empty | |
diners.preferences_text_hint |
string | REQUIRED, may be empty | partner-side LLM hints |
preferences.cuisine_preferred |
enum | REQUIRED, see §5 | |
preferences.cuisine_acceptable |
array |
REQUIRED, ≥1 | |
preferences.regional_authenticity_required |
bool | REQUIRED | |
preferences.menu_rotation_minimum_days |
int | REQUIRED, ≥1 | meals shouldn't repeat sooner |
preferences.tiffin_packaging |
enum | REQUIRED, see §5 | |
preferences.delivery_kind_preferred |
enum | REQUIRED, STRICT home_delivery | pickup_at_kitchen | central_locker_pickup |
|
preferences.budget_max_inr_per_period |
INR_INTEGER | REQUIRED | |
preferences.max_eta_minutes |
int | REQUIRED | tolerance against window |
preferences.kitchen_visit_friendly |
bool | REQUIRED | partner allows user inspection |
preferences.delivery_personnel_kyc_required |
bool | REQUIRED |
Anti-fabrication preamble (universal): no paid placement, no urgency text, no commission-influenced fields.
3. PROVIDER TOOLS
Tool 1: get_tiffin_subscription_estimates
PURPOSE: return subscription options across kitchens + plans
INPUT: §2 request body
OUTPUT: { options: TiffinSubscriptionOption[], result_token, expires_at }
SLA: p50 < 800ms, p95 < 1500ms
RATE LIMIT: ≤ 1/sec per user
Tool 2: get_kitchen_detail_with_menu
PURPOSE: kitchen profile + 14-day rolling menu
INPUT: { kitchen_id, request_id }
OUTPUT: KitchenDetail (§4)
SLA: p95 < 800ms
Tool 3: book_tiffin_subscription
PURPOSE: commit subscription + first delivery
INPUT: { option_id, payment_token, request_id, idempotency_key, user_phone, otp_required }
OUTPUT: { subscription_ref, status, fare_quote, first_delivery_iso, billing_setup_status }
SLA: p95 < 5000ms
IDEMPOTENCY: REQUIRED on idempotency_key
Tool 4: get_subscription_state
PURPOSE: live state with deliveries-this-period summary
INPUT: { subscription_ref, request_id }
OUTPUT: TiffinSubscriptionState (§4)
SLA: p95 < 600ms
RATE LIMIT: ≤ 1 every 60s
Tool 5: pause_subscription
INPUT: { subscription_ref, pause_from_iso, pause_until_iso, reason, request_id }
OUTPUT: { status, billing_credit_inr, resume_iso }
SLA: p95 < 1500ms
Tool 6: resume_subscription
INPUT: { subscription_ref, resume_from_iso, request_id }
OUTPUT: { status, next_billing_iso, next_delivery_iso }
SLA: p95 < 1500ms
Tool 7: skip_meal_for_date
INPUT: { subscription_ref, skip_date_iso, meal_kind, request_id }
OUTPUT: { status, billing_adjustment_inr }
SLA: p95 < 1000ms
Tool 8: swap_meal_or_request_special
PURPOSE: request a swap for one day's meal
INPUT: { subscription_ref, target_date_iso, meal_kind, swap_request_text, request_id }
OUTPUT: { status, swap_acknowledged, fare_delta_inr }
SLA: p95 < 1500ms
Tool 9: cancel_subscription
INPUT: { subscription_ref, reason, cancel_immediately, request_id }
OUTPUT: { status, refund_amount_inr, last_delivery_iso, refund_processing_days }
SLA: p95 < 2000ms
Tool 10: track_today_meal
PURPOSE: live tracking for today's delivery
INPUT: { subscription_ref, meal_kind, request_id }
OUTPUT: { status, eta_minutes, rider_name, rider_phone_masked, rider_lat, rider_lng }
SLA: p95 < 400ms
RATE LIMIT: ≤ 1 every 30s
Tool 11: rate_meal
PURPOSE: rate a specific meal post-delivery
INPUT: { subscription_ref, meal_iso, meal_kind, rating_5star, comment, request_id }
OUTPUT: { acknowledged: true }
SLA: p95 < 800ms
All eleven REQUIRED.
4. RESPONSE SHAPE
TiffinSubscriptionOption
id: string, REQUIRED
option_token: string, REQUIRED
expires_at: ISO_DATETIME, REQUIRED
subscription_kind: STRICT ENUM, REQUIRED
kitchen:
id: string, REQUIRED
merchant_id: string, REQUIRED
name: string, REQUIRED
brand: string, REQUIRED
cuisine_primary: STRICT ENUM, REQUIRED
cuisines_offered: array<enum>, REQUIRED, ≥1
veg_only_kitchen: boolean, REQUIRED
jain_meals_available: boolean, REQUIRED
halal_meals_available: boolean, REQUIRED
satvik_meals_available: boolean, REQUIRED
no_onion_no_garlic_available: boolean, REQUIRED
regional_authenticity_certified: boolean, REQUIRED
authenticity_authority: STRICT ENUM, REQUIRED
total_subscribers: int, REQUIRED, ≥0
kitchen_kind: STRICT ENUM, REQUIRED # cloud_kitchen | home_kitchen | dabba_kitchen | tiffin_co_op
partner_account_age_days: int, REQUIRED, ≥0
address:
line_1: string, REQUIRED
neighborhood: string, REQUIRED
city: string, REQUIRED
pincode: string, REQUIRED
lat: float, REQUIRED
lng: float, REQUIRED
google_place_id: 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
food_quality_score: float, REQUIRED, 0-5
portion_score: float, REQUIRED, 0-5
consistency_score: float, REQUIRED, 0-5
delivery_punctuality_score: float, REQUIRED, 0-5
packaging_score: float, REQUIRED, 0-5
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
food_handler_kyc_pct: int, REQUIRED, 0-100
kitchen_visit_friendly: boolean, REQUIRED
last_kitchen_inspection_iso: ISO_DATETIME, REQUIRED
tomo_field_team_audited: boolean, REQUIRED
photos:
thumbnail_url: URL, REQUIRED
hero_url: URL, REQUIRED
kitchen_photos_url: URL, REQUIRED
food_photos_url: URL, REQUIRED
ai_generated_photos: boolean, REQUIRED # MUST be false
meal_plan:
meals_per_day: STRICT ENUM, REQUIRED
rolling_menu_days: int, REQUIRED, ≥7
menu_rotation: array, REQUIRED, ≥7
- day_index: int, REQUIRED
day_label: string, REQUIRED # "Mon Week 1"
meals: array, REQUIRED, ≥1
- meal_kind: STRICT ENUM, REQUIRED # breakfast | lunch | dinner
dishes: array<TiffinDish>, REQUIRED, ≥1
fare:
total_period_inr: INR_INTEGER, REQUIRED
per_meal_avg_inr: INR_INTEGER, REQUIRED
base_per_meal_inr: INR_INTEGER, REQUIRED # standalone-equivalent
subscription_discount_pct: float, REQUIRED, 0-1
delivery_fee_inr_per_period: INR_INTEGER, REQUIRED
packaging_fee_inr_per_period: INR_INTEGER, REQUIRED
platform_fee_inr_per_period: INR_INTEGER, REQUIRED
gst_inr_per_period: INR_INTEGER, REQUIRED
fare_breakdown_text: string, REQUIRED
is_upfront_fare: boolean, REQUIRED
fare_locked_until_iso: ISO_DATETIME, REQUIRED
billing:
period_kind: STRICT ENUM, REQUIRED
charge_iso: ISO_DATETIME, REQUIRED
payment_method_required: STRICT ENUM, REQUIRED
prorated_first_period: boolean, REQUIRED
proration_method: STRICT ENUM, REQUIRED
refund_policy: STRICT ENUM, REQUIRED
delivery_meta:
delivery_kind: STRICT ENUM, REQUIRED
delivery_personnel_kyc_pct: int, REQUIRED, 0-100
delivery_partner_kind: STRICT ENUM, REQUIRED # in_house | third_party_aggregator | partner_owned
delivery_eta_buffer_minutes: int, REQUIRED # std deviation from window
late_delivery_30day_pct: float, REQUIRED, 0-1
cold_chain_compliant: boolean, REQUIRED # if perishable
spill_proof_seal: boolean, REQUIRED
packaging:
primary_packaging: STRICT ENUM, REQUIRED
cutlery_provided: boolean, REQUIRED
cutlery_material: STRICT ENUM, REQUIRED
napkins_provided: boolean, REQUIRED
reusable_dabba_supported: boolean, REQUIRED
user_keeps_dabba: boolean, REQUIRED
dabba_pickup_for_reuse: boolean, REQUIRED # tiffin co-op model
cancellation:
free_cancel_within_first_n_meals: int, REQUIRED, ≥0
cancel_charge_inr_per_remaining_period: INR_INTEGER, REQUIRED
exit_charge_inr: INR_INTEGER, REQUIRED
refund_processing_days: int, REQUIRED, ≥0
freshness:
data_last_synced_iso: ISO_DATETIME, REQUIRED
menu_last_updated_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_email: string, REQUIRED
customer_support_24x7: boolean, REQUIRED
in_app_chat_supported: boolean, REQUIRED
partner_subscriptions_served_30d: int, REQUIRED, ≥0
partner_subscription_completion_rate_30d: float, REQUIRED, 0-1
TiffinDish
id: string, REQUIRED
name: string, REQUIRED
description: string, REQUIRED
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
protein_g: float, REQUIRED
carbs_g: float, REQUIRED
fat_g: float, REQUIRED
fiber_g: float, REQUIRED
contains_palm_oil: boolean, REQUIRED
oil_used: STRICT ENUM, REQUIRED
sodium_mg: int, REQUIRED
photo_url: URL, REQUIRED
photo_ai_generated: boolean, REQUIRED # MUST be false
preparation_method: STRICT ENUM, REQUIRED
freshness_iso: ISO_DATETIME, REQUIRED # cooked-at time
KitchenDetail (returned by get_kitchen_detail_with_menu)
Superset of kitchen block in TiffinSubscriptionOption plus full 14-day rolling menu, expanded reviews, sample-meal photos, kitchen-walk-through video URL.
TiffinSubscriptionState (returned by get_subscription_state)
subscription_ref: string, REQUIRED
status: STRICT ENUM, REQUIRED
status_updated_iso: ISO_DATETIME, REQUIRED
status_history: array, REQUIRED, ≥1
period_summary:
current_period_start_iso: ISO_DATETIME, REQUIRED
current_period_end_iso: ISO_DATETIME, REQUIRED
meals_delivered_this_period: int, REQUIRED, ≥0
meals_skipped_by_user: int, REQUIRED, ≥0
meals_failed_by_partner: int, REQUIRED, ≥0
meals_remaining_this_period: int, REQUIRED, ≥0
current_period_inr_charged: INR_INTEGER, REQUIRED, ≥0
next_meal:
date_iso: ISO_DATE, REQUIRED
meal_kind: STRICT ENUM, REQUIRED
delivery_window_start_iso: ISO_DATETIME, REQUIRED
delivery_window_end_iso: ISO_DATETIME, REQUIRED
expected_dishes: array<dish_id>, REQUIRED, ≥1
expected_rider_kyc_verified: boolean, REQUIRED
paused:
is_paused: boolean, REQUIRED
paused_from_iso: ISO_DATETIME, REQUIRED
paused_until_iso: ISO_DATETIME, REQUIRED
billing_state:
next_charge_iso: ISO_DATETIME, REQUIRED
payment_method_status: STRICT ENUM, REQUIRED
auto_renew_active: boolean, REQUIRED
support_phone: string, REQUIRED
support_email: string, REQUIRED
Forbidden fields
paid_placement_score | sponsored_rank | promotion_priority |
fake_recent_subscriber_text | auto_inflate_subscriber_count |
ai_generated_photos (must equal false) | hidden_packaging_fee |
fake_food_handler_kyc_pct | undocumented_dabba_deposit
5. CONTROLLED VOCABULARIES
subscription_kind
weekly_breakfast_only | weekly_lunch_only | weekly_dinner_only |
weekly_breakfast_lunch | weekly_lunch_dinner | weekly_three_meals |
monthly_breakfast_only | monthly_lunch_only | monthly_dinner_only |
monthly_breakfast_lunch | monthly_lunch_dinner | monthly_three_meals |
quarterly_lunch_only | quarterly_three_meals
meal_plan.meals_per_day
breakfast_only | lunch_only | dinner_only |
breakfast_lunch | breakfast_dinner | lunch_dinner | three_meals
recurrence.pattern
mon_to_fri | mon_to_sat | every_day | weekdays_only_skip_holidays |
custom_days
delivery_address.place_kind
home | office | school | college | hostel | other
cuisine_*
hyderabadi | south_indian | north_indian | bengali | punjabi | gujarati |
maharashtrian | rajasthani | kerala | tamilian | andhra | konkani | goan |
mughlai | jain | satvik | regional_continental | global_fusion
kitchen.authenticity_authority
none | guru_authority_indian | regional_culinary_council | partner_internal | tomo_food_audit
kitchen.kitchen_kind
cloud_kitchen | home_kitchen | dabba_kitchen | tiffin_co_op | hotel_kitchen
kitchen.trust.fssai_grade
A | B | C | unrated
dietary_filters and dish.dietary_tags
veg | non_veg | egg | vegan | jain | halal | kosher | satvik |
no_onion_no_garlic | gluten_free | dairy_free | sugar_free | low_carb |
keto | paleo | high_protein | low_calorie
allergens
peanuts | tree_nuts | dairy | eggs | wheat | gluten | soy |
fish | shellfish | sesame | mustard
spice_level
mild | medium | spicy | very_spicy
dish.veg_or_non_veg
veg | non_veg | egg | vegan | jain
dish.preparation_method
deep_fried | shallow_fried | grilled | tandoor | baked | steamed |
boiled | sauteed | sun_cooked | slow_cooked | pressure_cooked
dish.oil_used
sunflower | mustard | groundnut | rice_bran | olive | coconut |
ghee | butter | palm | mixed | none
preferences.tiffin_packaging and packaging.primary_packaging
stainless_steel_dabba | bagasse | aluminum_foil | banana_leaf |
microwave_safe_plastic | paper_box | reusable_silicone | mixed
packaging.cutlery_material
plastic | wooden | bamboo | none
preferences.delivery_kind_preferred and delivery_meta.delivery_kind
home_delivery | pickup_at_kitchen | central_locker_pickup | drop_box_at_office
delivery_meta.delivery_partner_kind
in_house | third_party_aggregator | partner_owned
billing.period_kind
weekly | monthly | quarterly
billing.payment_method_required
upi_autopay | card_recurring_mandate | netbanking_emandate | wallet_auto_recharge
billing.proration_method
exact_per_meal_count | flat_first_period | no_proration
billing.refund_policy
unused_meals_credited | unused_meals_refunded_60pct | unused_meals_refunded_full |
no_refund_after_period_starts
TiffinSubscriptionState.status
pending_first_meal | active | paused_by_user | paused_by_partner |
billing_failed | renewal_failed | cancelled_by_user | cancelled_by_partner |
expired | failed
TiffinSubscriptionState.next_meal.meal_kind
breakfast | lunch | dinner
TiffinSubscriptionState.billing_state.payment_method_status
active | pending_authorization | failed_last_charge | mandate_revoked
cancel_subscription.reason
user_changed_address | unsatisfied_food_quality | unsatisfied_portion_size |
unsatisfied_punctuality | found_alternative | health_dietary_change |
moved_city | medical | other
pause_subscription.reason
travel | medical | hosting_guests | wfh_period | sabbatical | other
merchant_id resolution order
1. Google Place ID
2. FSSAI license number
3. partner_id + ":" + kitchen_id
6. TTBS DIMENSIONS
Per-domain weights (locked; tiffin override)
food (subscribe_tiffin): { time: 0.20, taste: 0.40, budget: 0.30, safety: 0.10 }
Time stays moderate (window-based, not minute-precise). Taste is the heart of tiffin (variety, regional authenticity, consistency). Budget rises (subscription pricing matters). Safety drops to 0.10 — repeat customer pattern + HARD FILTERS handle critical safety.
TIME
SIGNALS USED:
- delivery_meta.late_delivery_30day_pct (lower=better) weight 0.40
- delivery_meta.delivery_eta_buffer_minutes weight 0.20
- distance_from_user_km weight 0.20
- billing.refund_policy permissiveness weight 0.10
- cancellation.refund_processing_days weight 0.10
USER BAND HANDLING:
- "tight 1pm window" → late_delivery_30day_pct < 5%
TASTE
SIGNALS USED:
- kitchen.ratings.food_quality_score weight 0.20
- kitchen.ratings.consistency_score weight 0.20
- kitchen.regional_authenticity_certified weight 0.20
- cuisine_preferred match weight 0.20
- meal_plan.rolling_menu_days vs preferences.menu_rotation_minimum_days weight 0.10
- kitchen.kitchen_kind=home_kitchen (authenticity bias) weight 0.10
HARD FILTERS:
- dietary_filters not satisfiable
- allergens_to_avoid present in menu_rotation
- jain_meal_required AND jain_meals_available=false
- halal_required AND halal_meals_available=false
- regional_authenticity_required AND regional_authenticity_certified=false
BUDGET
SIGNALS USED:
- fare.total_period_inr vs band:
ok → 0–33rd percentile (city, period)
good → 33rd–66th
great → 66th+
- fare.subscription_discount_pct (higher=better) weight 0.30
- fare.is_upfront_fare=true weight 0.20
- cancellation.cancel_charge_inr_per_remaining_period (lower=better) weight 0.20
- cancellation.exit_charge_inr (lower=better) weight 0.15
- billing.refund_policy permissiveness weight 0.15
HARD FILTERS:
- fare.total_period_inr > preferences.budget_max_inr_per_period → drop
SAFETY
SIGNALS USED:
- kitchen.trust.fssai_grade (A=high) weight 0.30
- kitchen.trust.cleanliness_audit_score weight 0.20
- kitchen.trust.food_handler_kyc_pct weight 0.15
- kitchen.trust.kitchen_visit_friendly weight 0.10
- kitchen.trust.tomo_field_team_audited weight 0.10
- delivery_meta.delivery_personnel_kyc_pct (>80%) weight 0.10
- delivery_meta.cold_chain_compliant (perishable) weight 0.10
- delivery_meta.spill_proof_seal weight 0.05
- menu allergens overlap user.allergens_to_avoid HARD FILTER (drop kitchen)
HARD FILTERS:
- delivery_personnel_kyc_required AND kitchen kyc_pct < 80% → drop
- any allergen in menu present in user.allergens_to_avoid → drop kitchen
Hidden ranking factor
information_completeness_score weight 0.10.
7. COMPLETION CONTRACT
Like mobility.book_recurring_commute, this intent has TWO completion events.
Per-period settlement
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
{
"intent": "food.subscribe_tiffin",
"intent_version": "v1.0.0",
"event_kind": "period_settled",
"external_id": "TIFFIN-XYZ",
"subscription_ref": "TIFFIN-XYZ",
"amount_inr": 3800,
"closed_at": "2026-06-10T00:01:00+05:30",
"request_id": "req_tif_3k9p_...",
"status": "period_completed",
"period_start_iso": "2026-05-12T00:00:00+05:30",
"period_end_iso": "2026-06-09T23:59:59+05:30",
"meals_delivered": 24,
"meals_skipped": 2,
"meals_failed": 0,
"currency": "INR"
}
Subscription closure
POST /api/v1/cpc/mcp_provider/{tomo_partner_id}
{
"intent": "food.subscribe_tiffin",
"intent_version": "v1.0.0",
"event_kind": "subscription_closed",
"external_id": "TIFFIN-XYZ",
"subscription_ref": "TIFFIN-XYZ",
"amount_inr": 11400,
"closed_at": "2026-08-12T00:00:00+05:30",
"status": "completed",
"subscription_started_at": "2026-05-12T00:00:00+05:30",
"subscription_ended_at": "2026-08-11T23:59:59+05:30",
"total_periods_billed": 3,
"total_meals_delivered": 72,
"total_meals_skipped": 6,
"total_meals_failed": 1,
"currency": "INR",
"ratings_pending": true,
"notes": ""
}
Status enum (period): period_completed | period_partial_refund_credited | period_billing_failed
Status enum (closure): completed | cancelled_by_user_within_grace | cancelled_by_user_after_grace | cancelled_by_partner | expired_no_renew | failed
8. WIDGET
WIDGET TYPE: tiffin_subscription_options
SOURCE: src/widgets/types.ts
TYPE NAME: TiffinSubscriptionOptionsPayload
RENDERED IN: components/widgets/TiffinSubscriptionOptionsWidget.tsx
Default: 3 stacked rows showing kitchen name, cuisine, meals/day, fare per period with per-meal-avg, FSSAI grade badge. Tap row → kitchen detail with rolling 14-day menu, kitchen photos, sample meal photos, reviews → "Subscribe". Then TiffinSubscriptionDashboard with period progress + pause/resume + skip-meal + swap-meal controls.
9. CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
get_tiffin_subscription_estimates |
300s | inventory + pricing slow |
get_kitchen_detail_with_menu |
60s | menu may rotate |
get_subscription_state |
30s | period summary doesn't change often |
book_tiffin_subscription |
0s | |
| pause/resume/skip/swap | 0s | |
cancel_subscription |
0s | |
track_today_meal |
5s | live during delivery window |
| Failure responses | 0s |
10. ERROR CODES
| Code | HTTP | Meaning | TOMO behavior |
|---|---|---|---|
NO_KITCHENS_AVAILABLE |
503 | no kitchen serves the area | fall back |
OUT_OF_DELIVERY_RANGE |
400 | address outside coverage | surface |
OPTION_EXPIRED |
410 | option_token invalid | re-quote |
PAYMENT_METHOD_REQUIRED |
402 | no UPI Autopay / mandate | surface |
MANDATE_AUTH_FAILED |
402 | bank mandate auth declined | surface |
SUBSCRIPTION_NOT_FOUND |
404 | subscription_ref doesn't exist | surface |
ALREADY_CANCELLED |
409 | duplicate cancel | idempotent |
ALREADY_PAUSED |
409 | duplicate pause | idempotent |
BILLING_FAILED |
402 | last cycle declined | dunning flow |
MANDATE_REVOKED |
401 | user revoked at bank | re-onboard |
WINDOW_INFEASIBLE |
400 | window not coverable | surface |
MEAL_NOT_SCHEDULED |
404 | get for non-scheduled day | surface |
SWAP_REJECTED |
409 | partner cannot honor swap | surface alternate |
11. SANDBOX → PRODUCTION CHECKLIST
[ ] All §2 inputs validated, request_id echoed
[ ] get_tiffin_subscription_estimates returns ≥3 options
[ ] All §4 fields populated with real data
[ ] FSSAI license + grade present
[ ] regional_authenticity_certified backed by partner-internal cert
[ ] photo_ai_generated == false everywhere
[ ] Allergens complete on every menu_rotation dish
[ ] Macros (calories, protein, carbs, fat) on every dish
[ ] book_tiffin_subscription returns valid subscription_ref + first_delivery
[ ] UPI Autopay / mandate setup tested
[ ] First meal delivered on active_from_iso
[ ] track_today_meal returns rider location
[ ] pause/resume/skip/swap flows tested with billing math
[ ] cancel respects free_cancel_within_first_n_meals grace
[ ] Per-period CPC fires on each billing close ≤24h
[ ] Subscription-closure CPC ≤60s of cancel
[ ] HMAC verification passes
[ ] No forbidden fields anywhere
[ ] No paid_placement / sponsored signals
[ ] customer_support_24x7 verified by TOMO call
[ ] Kitchen visit (kitchen_visit_friendly=true) tested
[ ] FSSAI license uploaded
[ ] All delivery personnel KYC artifacts uploaded
12. ANTI-FABRICATION RULES
RULE 1 — No paid placement signals.
RULE 2 — Ratings unrounded floats from real subscribers.
RULE 3 — No fake total_subscribers inflation.
TOMO compares stated count vs partner CPC ledger; mismatch >5% = breach.
RULE 4 — No fake regional_authenticity_certified.
Must back claim with auth-authority cert. Self-attesting "regional" without
cert + serving Punjabi food labelled as Andhra = breach.
RULE 5 — No AI-generated photos. ai_generated_photos MUST be false.
RULE 6 — Allergens_present must be complete.
RULE 7 — Macros honest within ±15% of computed nutrition.
RULE 8 — No commission-based response shaping.
RULE 9 — Skipped meals credited honestly.
meals_skipped_by_user must produce billing_credit_inr per proration policy.
Charging full period when user skipped 8 of 26 meals = breach.
RULE 10 — Failed meals are not absorbed silently.
meals_failed_by_partner > 0 must trigger user-visible billing credit.
Hiding failed meals to preserve completion_rate_30d = severe breach.
RULE 11 — Auto-renew honest.
billing.auto_renew=true requires user notification 7 days before charge.
RULE 12 — Pause/resume math honest.
pause credit = (paused_days / total_period_days) × period_inr, rounded down.
RULE 13 — Mandate revocation respected.
RULE 14 — Kitchen visit promise honored.
kitchen_visit_friendly=true means user can show up unannounced during
business hours and inspect kitchen. Refusing = breach.
RULE 15 — Menu rotation honored.
rolling_menu_days ≥ user's menu_rotation_minimum_days. Repeating same
meal twice within stated rotation window = breach.
RULE 16 — Delivery personnel KYC real.
delivery_personnel_kyc_pct must reflect partner's actual KYC artifact
collection. Inflating to attract trust-conscious users = breach.
RULE 17 — Reusable dabba pickup honest.
reusable_dabba_supported=true + dabba_pickup_for_reuse=true means partner
actually collects + sanitizes dabbas. Charging dabba deposit then not
collecting = breach.
VERSION HISTORY
v1.0.0 — 2026-05-10 — Initial spec