Intent Spec — entertainment.book_sports_event
FULL ID: entertainment.book_sports_event
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-12
DOMAIN: entertainment
PRIMARY AGENT: EntertainmentAgent
TTBS WEIGHTS: time=0.20 taste=0.40 budget=0.20 safety=0.20
User books a ticket to a live sports event — cricket (IPL, internationals, domestic), football (ISL, EPL screenings, friendlies), kabaddi (Pro Kabaddi League), tennis, badminton, motorsport, eSports finals. TASTE-dominant because the user is choosing a fixture / team / sport. Distinct from entertainment.book_concert_ticket (music) and entertainment.book_event_venue (renting a venue).
Partner exemplars: BookMyShow (IPL official), Paytm Insider, District by Zomato, official board portals (BCCI ticketing for internationals), ISL official ticketing, Pro Kabaddi League.
SECTION 1 — INTENT IDENTITY
User wants to attend a live sports fixture. Distinct from:
- Watching the match on TV →
entertainment.subscribe_streaming(Hotstar / JioCinema) - Booking a sports VENUE for private play → out of scope (v1.1+
lifestyle.book_sports_facility) - Sports betting / fantasy → not a TOMO intent
Single intent per booking. Season passes are single intent (one purchase).
SECTION 2 — NATURAL LANGUAGE COVERAGE
CLASSIFIES IN
- "Book IPL tickets RCB vs CSK"
- "India vs Australia ODI tickets"
- "Pro Kabaddi League final tickets"
- "ISL Bengaluru FC home game"
- "F1 Indian GP tickets"
- "Tennis tournament tickets in Pune"
- "MMA fight night ticket"
- "PKL semi-final cheapest stand"
- "Cricket test match all 5 days"
- "Hockey league finals"
CLASSIFIES OUT — BORDERLINE NO
- "Stream the match" →
entertainment.subscribe_streaming - "Book a turf to play cricket" → out of scope v1
- "IPL on Hotstar" →
entertainment.subscribe_streaming - "Book a watch party at a bar" → ambiguous; closer to
food.book_dine_in
MULTI-INTENT TRIGGERS
- "IPL final + flight + hotel" →
entertainment.book_sports_event+travel.book_flight+travel.book_hotel - "Match + ride home" →
entertainment.book_sports_event+mobility.book_intracity_ride
SECTION 3 — INPUT (TOMO → PROVIDER)
{
"intent": "entertainment.book_sports_event",
"request_id": "req_01J9Z...",
"user_locale": "en-IN",
"user_location": { "lat": 17.4475, "lng": 78.3563, "max_radius_km": 80, "city": "Hyderabad" },
"preferences": {
"sport": "cricket", // STRICT ENUM §6
"league": "ipl", // STRICT ENUM §6 nullable
"team_preferences": ["sunrisers_hyderabad", "royal_challengers_bangalore"], // free-form ids, partner normalises
"match_window": {
"start": "2026-05-15T00:00:00+05:30",
"end": "2026-05-25T23:59:59+05:30"
},
"seat_count": 4,
"stand_preference": ["premium", "general_north"],
"indoor_outdoor": "outdoor", // STRICT ENUM §6
"ok_with_high_security": true // big-match security can be intense; some users opt out
},
"ttbs_user_band": { "time": "balanced", "taste": "great", "budget": "good", "safety": "balanced" },
"session_context": { "tomo_session_id": "ses_01J9Z...", "user_dna_hash": "dna_v3_a7c9..." }
}
| Field | Type | Constraint | Notes |
|---|---|---|---|
intent |
string | REQUIRED, STRICT ENUM | Always entertainment.book_sports_event |
preferences.sport |
enum | REQUIRED, STRICT ENUM §6 | |
preferences.league |
enum | null | REQUIRED nullable, STRICT ENUM §6 | |
preferences.team_preferences |
array |
REQUIRED, may be empty | Partner normalises against official team IDs |
preferences.indoor_outdoor |
enum | REQUIRED, STRICT ENUM §6 | Drives weather / venue filter |
Anti-fabrication preamble: Touts / scalper listings forbidden. Tickets must be primary-market or official-resale (e.g. NBA Verified). Surge / dynamic pricing must be disclosed.
SECTION 4 — PROVIDER TOOLS
(Same 4-tool pattern: search_sports_events / get_seat_map / create_booking / cancel_booking. SLAs identical.)
SECTION 5 — RESPONSE SHAPE
SportsEventListing
SportsEventListing:
show_id: { type: string, constraint: REQUIRED }
match:
sport: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
league: { type: enum, constraint: REQUIRED nullable, STRICT ENUM §6 }
match_format: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [t20, odi, test, knockout, final, group_stage, friendly, league_game, semi_final] }
home_team: { type: string, constraint: REQUIRED }
away_team: { type: string, constraint: REQUIRED nullable, semantics: "null for individual sports e.g. tennis tournament" }
tournament_round: { type: string, constraint: REQUIRED nullable }
is_official_listing: { type: boolean, constraint: REQUIRED, semantics: "primary market or official resale only" }
venue:
venue_id: { type: string, constraint: REQUIRED }
name: { type: string, constraint: REQUIRED }
venue_type:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [stadium, indoor_arena, racing_circuit, court_complex, esports_arena]
address: { type: string, constraint: REQUIRED }
location: { type: object, shape: { lat, lng }, constraint: REQUIRED }
distance_from_user_km: { type: float, constraint: REQUIRED, 0-500 }
capacity_total: { type: int, constraint: REQUIRED, 500-150000 }
roofed: { type: boolean, constraint: REQUIRED, semantics: "matters for outdoor sports in monsoon" }
accessibility:
wheelchair_accessible: { type: boolean, constraint: REQUIRED }
accessible_section_id: { type: string, constraint: REQUIRED nullable }
match_time:
start: { type: string, constraint: REQUIRED, ISO_DATETIME }
estimated_end: { type: string, constraint: REQUIRED, ISO_DATETIME }
gates_open_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
advance_booking_cutoff: { type: string, constraint: REQUIRED, ISO_DATETIME }
pricing:
sections:
type: array<SectionPrice>
constraint: REQUIRED, ≥1
shape:
section_id: { type: string, constraint: REQUIRED }
section_label: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [general, upper_tier, lower_tier, premium, vip, hospitality_box, pavilion, north_stand, south_stand, east_stand, west_stand] }
base_price_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
booking_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
gst_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
total_per_ticket_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
includes_food: { type: boolean, constraint: REQUIRED }
includes_alcohol: { type: boolean, constraint: REQUIRED }
dynamic_pricing_active: { type: boolean, constraint: REQUIRED }
availability:
seats_available_total: { type: int, constraint: REQUIRED, ≥0 }
seats_available_by_section: { type: object<section_id,int>, constraint: REQUIRED }
fast_selling: { type: boolean, constraint: REQUIRED, semantics: "TRUE only when ratio < 20%" }
policies:
cancellation:
cutoff_minutes_before_start: { type: int, constraint: REQUIRED, ≥0 }
refund_percent: { type: int, constraint: REQUIRED, 0-100 }
age_restriction_enforced: { type: boolean, constraint: REQUIRED }
photography_allowed: { type: boolean, constraint: REQUIRED }
re_entry_allowed: { type: boolean, constraint: REQUIRED }
outside_food_allowed: { type: boolean, constraint: REQUIRED }
bag_size_limit_litres: { type: int, constraint: REQUIRED, ≥0 }
prohibited_items_url: { type: string, constraint: REQUIRED, HTTPS URL }
abandonment_refund_policy: { type: string, constraint: REQUIRED, semantics: "match abandoned due to rain etc — partner policy" }
partner_reference:
source: { type: string, constraint: REQUIRED }
deeplink: { type: string, constraint: REQUIRED, HTTPS URL }
SeatMap, Booking, CancellationResult — same shapes as movie_ticket spec §5.
FORBIDDEN FIELDS
paid_placement_score,ad_bid,sponsored_rank,promotion_priority,kickback_amountartificial_urgency_textai_generated_photocommission_padded_pricescalper_listing(resale at ≥1.5x face value without official-resale authorisation = forbidden)unofficial_listing(is_official_listing=false cannot rank above true listings)
SECTION 6 — CONTROLLED VOCABULARIES
preferences.sport:
values: { cricket, football, kabaddi, hockey, tennis, badminton, basketball, motorsport_f1, motorsport_motogp, esports, mma, boxing, wrestling, athletics }
preferences.league:
values: { ipl, womens_premier_league, ranji_trophy, india_internationals, isl, durand_cup, pkl, hil, atp_pune, premier_badminton, indian_gp, motogp_india, esports_premier_league, ufc_india, pwl, ipl_auction_event }
match.match_format:
values: { t20, odi, test, knockout, final, group_stage, friendly, league_game, semi_final }
venue.venue_type:
values: { stadium, indoor_arena, racing_circuit, court_complex, esports_arena }
pricing.sections.section_label:
values: { general, upper_tier, lower_tier, premium, vip, hospitality_box, pavilion, north_stand, south_stand, east_stand, west_stand }
indoor_outdoor: { values: { indoor, outdoor, either } }
SECTION 7 — TTBS DIMENSIONS
TIME (weight = 0.20):
signals_used: [distance, match_time fit, advance_booking_cutoff]
TASTE (weight = 0.40):
signals_used:
- sport match
- league match
- team_preferences (home_team OR away_team intersects)
- match_format match (T20 vs Test = very different audience)
- DNA history
weighting:
sport: 0.20
league: 0.20
team: 0.30
format: 0.20
dna: 0.10
BUDGET (weight = 0.20):
signals_used: [pricing min, dynamic_pricing_active]
SAFETY (weight = 0.20):
signals_used:
- venue.accessibility match
- venue.roofed (when outdoor + monsoon season)
- policies.bag_size_limit_litres (extreme limits frustrate users)
- is_official_listing (FALSE = filter out)
weighting:
official: 0.40
accessibility: 0.30
weather: 0.20
bag_policy: 0.10
SECTION 8 — COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/<your_partner_id>
Body:
{
"intent": "entertainment.book_sports_event",
"external_id": "<booking_id>",
"request_id": "<request_id>",
"amount_inr": 3200,
"gst_inr": 576,
"tips_inr": 0,
"pass_through_inr": 0,
"closed_at": "2026-05-22T22:00:00+05:30",
"status": "completed",
"seat_count": 4,
"sport": "cricket",
"league": "ipl",
"section_label": "general"
}
HMAC, 5-min replay, NET-only commission.
SECTION 9 — WIDGET
SportsEventWidget (planned). Field mapping: home_team vs away_team → header; venue + distance → subline 1; match_time + match_format → subline 2; pricing min → "From ₹X"; fast_selling → red pill; team logos (real, not AI).
SECTION 10 — CACHING POLICY
| Call | TTL |
|---|---|
| search_sports_events | 60s |
| get_seat_map | NO CACHE |
| create_booking | NO CACHE |
| cancel_booking | NO CACHE |
| Fixture metadata (team logos, league rules) | 12h |
SECTION 11 — ERROR CODES
(Same as concert + MATCH_RESCHEDULED (200 advisory), MATCH_ABANDONED_REFUND_PENDING (200 status).)
SECTION 12 — SANDBOX → PRODUCTION CHECKLIST
[ ] All four tools implemented
[ ] is_official_listing=true verified via official board / league agreement
[ ] Cancellation / abandonment refund policy disclosed
[ ] Real team logos under official licensing
[ ] No scalper or above-face-value listings without official-resale authorisation
[ ] HMAC + amount_inr=NET in CPC
[ ] Compliance: GSTIN, venue entertainment licenses, official board partnership letters, privacy policy
SECTION 13 — ANTI-FABRICATION RULES
RULE 1: No paid_placement / ad / kickback. Rejects response.
RULE 2: is_official_listing=true requires uploaded official partnership letter
from the relevant board / league. Touts / scalpers = immediate suspension
+ reporting to BCCI / ISL / etc.
RULE 3: Resale listings above face value require explicit official-resale
authorisation (e.g. NBA Verified-style programmes).
RULE 4: fast_selling=true only when ratio < 20%. Same enforcement.
RULE 5: dynamic_pricing_active=true means partner discloses pricing fluctuates.
Hidden dynamic markups = suspension.
RULE 6: AI-generated team/player/venue imagery forbidden. Licensed media only.
RULE 7: abandonment_refund_policy must be honoured. Match abandoned + refund
denied = consumer protection issue + suspension.
RULE 8: Bag-size / prohibited-items policy must be displayed BEFORE checkout.
Hiding draconian policies until gate = customer harm = suspension.
RULE 9: No "Top Pick" / "TOMO Recommended" badges. TTBS source-blind.
RULE 10: team_preferences in input must be normalised to official team IDs.
False team matches (e.g. listing RCB game when user asked CSK) =
deception = suspension.
RULE 11: For sports under anti-corruption review (IPL, etc.) partner must
co-operate with TOMO and the relevant board on any flagged listing.
RULE 12: includes_alcohol must reflect venue's actual licensing — alcohol-
ban states / dry days must respect law.
VERSION HISTORY
v1.0.0 — 2026-05-12 — Initial spec. NET commission base. TASTE-dominant (0.40)
— fixture / team / sport decision. Official-listing
requirement is consumer-protection floor.