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.0entertainment.book_sports_event

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_amount
  • artificial_urgency_text
  • ai_generated_photo
  • commission_padded_price
  • scalper_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.