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.0finance.buy_travel_insurance

Intent Spec — finance.buy_travel_insurance

FULL ID:       finance.buy_travel_insurance
VERSION:       v1.0.0
STATUS:        draft
LAST UPDATED:  2026-05-13
DOMAIN:        finance
PRIMARY AGENT: FinanceAgent
TTBS WEIGHTS:  time=0.30 taste=0.15 budget=0.25 safety=0.30

User buys travel insurance for a domestic or international trip. Single-trip or multi-trip (annual), geographic-zone-priced (Schengen, US-Canada, worldwide-excl-US, Asia, India-domestic), Schengen-VFS compliant where needed, with optional COVID, adventure-sports, baggage, trip-cancellation, and student/senior variants.

Partner exemplars: Policybazaar, Acko Travel, Tata AIG Travel, ICICI Lombard Travel, Bajaj Allianz Travel, HDFC ERGO Travel, Reliance Travel, Bharti AXA Travel, Religare Travel.


SECTION 1 — INTENT IDENTITY

User wants short-term travel insurance for a specific trip or annual multi-trip cover. Distinct from:

  • finance.buy_health_insurance — year-round indemnity health cover (domestic)
  • finance.buy_term_insurance / finance.buy_motor_insurance — non-trip products
  • Visa application — out of scope v1; compliance.apply_visa if introduced
  • Hotel / flight cancellation insurance bundled by OTAs — TOMO-level travel insurance is unbundled

Single intent per trip OR per annual multi-trip policy. Group travel up to 6 insured under one policy via insured_members array.


SECTION 2 — NATURAL LANGUAGE COVERAGE

CLASSIFIES IN

  • "Travel insurance for my Schengen visa"
  • "US trip insurance, 2 weeks in October"
  • "Annual multi-trip insurance for business travel"
  • "Insurance for Goa trip next week"
  • "Student travel insurance for studying in UK"
  • "Senior parent travel insurance, USA visit"
  • "Cheapest Schengen visa insurance"
  • "Trip cancellation cover for our Europe holiday"
  • "Travel insurance with adventure sports cover for our Manali trip"
  • "Family travel insurance Dubai 5 days"

CLASSIFIES OUT — BORDERLINE NO

  • "Buy life insurance" → finance.buy_term_insurance
  • "Health insurance for parents" → finance.buy_health_insurance
  • "Book a flight" → travel.book_flight
  • "Book a hotel" → travel.book_hotel
  • "Visa application" → out of scope v1
  • "Forex card" → finance.book_financial_advisor_session (v1.1+ dedicated)
  • "File travel insurance claim" → v1.1+ finance.file_travel_claim

MULTI-INTENT TRIGGERS

  • "Book flight + travel insurance" → travel.book_flight + finance.buy_travel_insurance
  • "Book hotel + flight + travel insurance + forex" → composite mission
  • "Adventure trip + insurance" → travel.book_adventure_activity + finance.buy_travel_insurance

SECTION 3 — INPUT (TOMO → PROVIDER)

{
  "intent": "finance.buy_travel_insurance",
  "request_id": "req_01J9Z...",
  "user_locale": "en-IN",
  "user_currency": "INR",
  "user_location": { "lat": 17.4475, "lng": 78.3563, "city": "Hyderabad", "pincode": "500032" },
  "trip_type": "single_trip",                          // STRICT ENUM §6
  "trip": {
    "origin_country": "IN",                             // ISO_3166_2
    "destination_countries": ["FR", "DE", "IT"],        // ISO_3166_2 array; ≥1
    "destination_zone": "schengen",                     // STRICT ENUM §6
    "departure_date": "2026-10-15",                     // ISO_DATE
    "return_date": "2026-10-26",                        // ISO_DATE; single_trip only
    "trip_duration_days": 12,
    "trip_purpose": "leisure",                          // STRICT ENUM §6
    "annual_max_trip_duration_days": null               // REQUIRED for multi-trip; null for single_trip
  },
  "insured_members": [
    {
      "first_name": "Rakesh", "last_name": "Kumar",
      "date_of_birth": "1985-04-18",
      "gender": "male",
      "passport_number_last4": "5678",
      "passport_expiry": "2030-03-15",
      "pre_existing_conditions": [],                    // STRICT ENUM array §6
      "is_proposer": true
    },
    {
      "first_name": "Anita", "last_name": "Kumar",
      "date_of_birth": "1988-09-12",
      "gender": "female",
      "passport_number_last4": "9012",
      "passport_expiry": "2031-06-22",
      "pre_existing_conditions": [],
      "is_proposer": false
    }
  ],
  "cover_preferences": {
    "sum_insured_usd": 100000,                          // USD denomination for international
    "currency_of_cover": "USD",                          // STRICT ENUM §6
    "schengen_compliant_required": true,                // ≥€30k medical mandate
    "addons_required": ["covid_cover", "adventure_sports_amateur", "trip_cancellation"],
    "preferred_insurers": []
  },
  "ttbs_user_band": {
    "time":   "fast",
    "taste":  "balanced",
    "budget": "good",
    "safety": "good"
  },
  "session_context": { "tomo_session_id": "ses_01J9Z...", "user_dna_hash": "dna_v3_a7c9..." }
}
Field Type Constraint Notes
intent string REQUIRED, STRICT ENUM Always finance.buy_travel_insurance
trip_type enum REQUIRED, STRICT ENUM §6 single_trip / annual_multi_trip / student / senior
trip.destination_countries array REQUIRED, ISO_3166_2, min 1
trip.destination_zone enum REQUIRED, STRICT ENUM §6 Drives premium banding
trip.departure_date string REQUIRED, ISO_DATE ≥ today + insurer-min lead time
trip.return_date string REQUIRED nullable Non-null for single_trip / student / senior
trip.annual_max_trip_duration_days int REQUIRED nullable Non-null for annual_multi_trip
insured_members array REQUIRED, min 1, max 6 Each member needs passport data for international
insured_members[].pre_existing_conditions array REQUIRED, STRICT ENUM §6 May be empty
cover_preferences.sum_insured_usd int REQUIRED, ≥10000 USD for international; INR for domestic
cover_preferences.currency_of_cover enum REQUIRED, STRICT ENUM §6 USD / EUR / INR
cover_preferences.schengen_compliant_required bool REQUIRED When TRUE, partner must guarantee ≥€30k medical

Anti-fabrication preamble: Provider must guarantee Schengen-compliant medical cover (≥€30,000) when destination_zone is schengen / europe AND schengen_compliant_required=TRUE. Visa rejection due to non-compliant policy = customer-harm + suspension. COVID cover claims must be backed by partner's IRDAI-filed disclosure as of quote timestamp.


SECTION 4 — PROVIDER TOOLS

Tool 1: search_travel_quotes

PURPOSE:      Up to 12 quotes matching trip + members + addons
SLA:          p50 ≤ 600ms, p95 ≤ 2000ms, p99 ≤ 4000ms
RATE LIMIT:   90 req/min (high — users compare often)
IDEMPOTENCY:  request_id; 5min cache (premiums table-driven)
RETRY:        1 on 429, 2 on 5xx

Tool 2: confirm_quote_and_kyc

PURPOSE:      Lock quote + KYC + passport verification
SLA:          p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT:   45 req/min
IDEMPOTENCY:  request_id
RETRY:        No retry

Tool 3: issue_policy

PURPOSE:      Issue policy after payment; instant for most travel products
SLA:          p50 ≤ 1500ms, p95 ≤ 4000ms, p99 ≤ 8000ms
RATE LIMIT:   45 req/min
IDEMPOTENCY:  request_id
RETRY:        No retry on issuance

Tool 4: cancel_or_freelook

PURPOSE:      Pre-departure cancellation OR free-look (travel-specific rules)
SLA:          p50 ≤ 1200ms, p95 ≤ 3500ms
RATE LIMIT:   30 req/min
IDEMPOTENCY:  policy_id
RETRY:        1 on 5xx

Tool 5: extend_policy

PURPOSE:      Extend coverage when trip overruns
SLA:          p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT:   30 req/min
IDEMPOTENCY:  policy_id
RETRY:        1 on 5xx

SECTION 5 — RESPONSE SHAPE

TravelQuote

TravelQuote:
  quote_id: { type: string, constraint: REQUIRED, opaque }
  insurer:
    insurer_id: { type: string, constraint: REQUIRED }
    name: { type: string, constraint: REQUIRED }
    irdai_registration_number: { type: string, constraint: REQUIRED }
    claim_settlement_ratio_pct: { type: float, constraint: REQUIRED, 0-100 }
    travel_claim_settlement_days_avg: { type: float, constraint: REQUIRED, ≥0 }
    solvency_ratio: { type: float, constraint: REQUIRED, 1.0-5.0 }
    global_assistance_partner: { type: string, constraint: REQUIRED, semantics: "e.g. Allianz Global Assistance, AXA Assistance" }

  product_name: { type: string, constraint: REQUIRED }
  product_uin: { type: string, constraint: REQUIRED }
  trip_type: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }

  destination_zone: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
  is_schengen_compliant: { type: boolean, constraint: REQUIRED, semantics: "Guarantees ≥€30k medical for Schengen visa" }

  cover_amounts:
    medical_emergency_usd: { type: int, constraint: REQUIRED, ≥0 }
    medical_evacuation_usd: { type: int, constraint: REQUIRED, ≥0 }
    repatriation_remains_usd: { type: int, constraint: REQUIRED, ≥0 }
    dental_emergency_usd: { type: int, constraint: REQUIRED, ≥0 }
    accidental_death_usd: { type: int, constraint: REQUIRED, ≥0 }
    permanent_disability_usd: { type: int, constraint: REQUIRED, ≥0 }
    baggage_loss_usd: { type: int, constraint: REQUIRED, ≥0 }
    baggage_delay_usd: { type: int, constraint: REQUIRED, ≥0 }
    passport_loss_usd: { type: int, constraint: REQUIRED, ≥0 }
    trip_cancellation_usd: { type: int, constraint: REQUIRED, ≥0, semantics: "0 if addon not included" }
    trip_curtailment_usd: { type: int, constraint: REQUIRED, ≥0 }
    trip_delay_usd: { type: int, constraint: REQUIRED, ≥0 }
    missed_connection_usd: { type: int, constraint: REQUIRED, ≥0 }
    hijacking_distress_usd: { type: int, constraint: REQUIRED, ≥0 }
    personal_liability_usd: { type: int, constraint: REQUIRED, ≥0 }

  deductible_usd: { type: int, constraint: REQUIRED, ≥0 }
  co_pay_pct: { type: int, constraint: REQUIRED, 0-30 }

  premium_breakdown:
    base_premium_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    age_loading_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    addon_premium_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    gst_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
    total_payable_inr: { type: int, constraint: REQUIRED, INR_INTEGER }

  policy_start_date: { type: string, constraint: REQUIRED, ISO_DATE }
  policy_end_date: { type: string, constraint: REQUIRED, ISO_DATE }

  addons_included:
    type: array<Addon>
    constraint: REQUIRED, may be empty
    shape:
      code: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
      label: { type: string, constraint: REQUIRED }
      sub_limit_usd: { type: int, constraint: REQUIRED, ≥0 }
      premium_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }

  exclusions_summary:
    type: array<enum>
    constraint: REQUIRED, STRICT ENUM §6
    semantics: "Standard exclusions explicitly disclosed"

  pre_existing_coverage:
    type: enum
    constraint: REQUIRED, STRICT ENUM §6
    values: [none, life_threatening_only, full]

  assistance_helpline_phone: { type: string, constraint: REQUIRED, E.164, semantics: "24×7 multilingual" }
  cashless_hospital_network_size: { type: int, constraint: REQUIRED, ≥0 }

  instant_issuance_possible: { type: boolean, constraint: REQUIRED }
  estimated_issuance_minutes: { type: int, constraint: REQUIRED, 1-1440 }

  policy_wording_url: { type: string, constraint: REQUIRED, HTTPS URL }
  customer_information_sheet_url: { type: string, constraint: REQUIRED, HTTPS URL }

  partner_reference:
    source: { type: string, constraint: REQUIRED }
    deeplink: { type: string, constraint: REQUIRED, HTTPS URL }

KYCResult

KYCResult:
  kyc_id: { type: string, constraint: REQUIRED }
  quote_id: { type: string, constraint: REQUIRED }
  kyc_status:
    type: enum
    constraint: REQUIRED, STRICT ENUM §6
    values: [verified_passport, verified_aadhaar, verified_pan, pending_manual, failed]
  passport_verification_status:
    type: enum
    constraint: REQUIRED, STRICT ENUM §6
    values: [verified, mismatch, expired_before_return, pending]
  documents_pending: { type: array<string>, constraint: REQUIRED, may be empty }
  expires_at: { type: string, constraint: REQUIRED, ISO_DATETIME }

IssuedPolicy

IssuedPolicy:
  policy_id: { type: string, constraint: REQUIRED, immutable }
  policy_number: { type: string, constraint: REQUIRED }
  insurer_id: { type: string, constraint: REQUIRED }
  product_uin: { type: string, constraint: REQUIRED }
  trip_type: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
  policy_start_date: { type: string, constraint: REQUIRED, ISO_DATE }
  policy_end_date: { type: string, constraint: REQUIRED, ISO_DATE }
  is_schengen_compliant: { type: boolean, constraint: REQUIRED }
  total_paid_inr: { type: int, constraint: REQUIRED, INR_INTEGER }
  policy_pdf_url: { type: string, constraint: REQUIRED, HTTPS URL, semantics: "Visa-compliant document; English; insurer letterhead" }
  visa_letter_url: { type: string, constraint: REQUIRED nullable, HTTPS URL, semantics: "Standalone Schengen-compliant letter when needed" }
  insured_members_count: { type: int, constraint: REQUIRED, ≥1 }
  assistance_helpline_phone: { type: string, constraint: REQUIRED, E.164 }
  emergency_evacuation_phone: { type: string, constraint: REQUIRED, E.164 }
  freelook_period_days: { type: int, constraint: REQUIRED, 0-15, semantics: "0 if trip has started" }

ExtensionResult

ExtensionResult:
  policy_id: { type: string, constraint: REQUIRED }
  extended_until: { type: string, constraint: REQUIRED, ISO_DATE }
  additional_premium_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
  extension_status:
    type: enum
    constraint: REQUIRED, STRICT ENUM §6
    values: [extended, declined_pre_existing_claim, declined_max_duration, payment_pending]

CancellationResult

CancellationResult:
  policy_id: { type: string, constraint: REQUIRED }
  cancelled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
  refund_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
  refund_method: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
  refund_eta_days: { type: int, constraint: REQUIRED, 0-30 }
  cancellation_reason: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
  is_freelook_cancellation: { type: boolean, constraint: REQUIRED }

FORBIDDEN FIELDS

  • paid_placement_score, ad_bid, sponsored_rank, kickback_amount
  • artificial_urgency_text ("Visa rejection guarantee!" type misleading)
  • ai_generated_photo for insurer / assistance partner imagery
  • fabricated_schengen_compliance (false schengen_compliant=true when actual medical < €30k)
  • inflated_claim_settlement_ratio
  • editor_recommended, tomo_pick
  • false_covid_cover (covid_cover addon claimed but not in actual product disclosure)

SECTION 6 — CONTROLLED VOCABULARIES

trip_type:
  values:
    single_trip:        "One-off trip, fixed dates"
    annual_multi_trip:  "Multiple trips in 12 months; per-trip cap"
    student:            "Long-stay (>180 days) educational travel"
    senior:             "60+ traveller variant with senior-specific terms"

trip.destination_zone:
  values:
    schengen:            "26 Schengen-area countries"
    europe_non_schengen: "UK, Ireland, etc."
    usa_canada:          "USA + Canada"
    asia_excl_japan:     "Asian destinations excluding Japan"
    japan:               "Japan-specific (priced separately)"
    worldwide_excl_us:   "Global excluding USA / Canada"
    worldwide_inc_us:    "Global including USA / Canada"
    india_domestic:      "India domestic travel"

trip.trip_purpose:
  values: [leisure, business, education, medical_tourism, religious_pilgrimage, sports, conference]

cover_preferences.currency_of_cover:
  values: [USD, EUR, INR, GBP, AUD, JPY, CAD]

insured_members[].pre_existing_conditions:
  values:
    none, hypertension, diabetes_type1, diabetes_type2, cardiac, cancer_remission,
    kidney_disease, liver_disease, mental_health, autoimmune, respiratory_chronic,
    neurological, pregnancy, other_disclosed

cover_preferences.addons_required / addons_included.code:
  values:
    covid_cover:                "COVID treatment + quarantine"
    adventure_sports_amateur:   "Skiing, scuba, trekking ≤6000m (non-professional)"
    adventure_sports_pro:       "Professional adventure activities"
    trip_cancellation:          "Pre-departure cancellation reasons"
    trip_interruption:          "Post-departure curtailment"
    trip_delay:                 "Common-carrier delay benefit"
    baggage_protection_extra:   "Higher baggage limit"
    home_burglary:              "Cover while travelling"
    gadget_protection:          "Electronics protection"
    rental_car_excess:          "CDW excess waiver"
    sports_equipment:           "Equipment cover"
    cruise_cover:               "Cruise-specific perils"

exclusions_summary:
  values:
    self_inflicted, intoxication, illegal_activity, war_terrorism,
    pre_existing_uncovered, professional_sport, pregnancy_routine,
    nuclear, mental_health_uncovered, suicide_within_12m

pre_existing_coverage:
  values: [none, life_threatening_only, full]

kyc_status: [verified_passport, verified_aadhaar, verified_pan, pending_manual, failed]

passport_verification_status: [verified, mismatch, expired_before_return, pending]

extension_status: [extended, declined_pre_existing_claim, declined_max_duration, payment_pending]

cancellation_reason:
  values: [pre_departure_voluntary, freelook, visa_rejected, trip_cancelled_other_reason, duplicate_policy]

refund_method: [original_payment, bank_transfer, cheque]

SECTION 7 — TTBS DIMENSIONS

TIME (weight = 0.30):
  signals_used:
    - instant_issuance_possible
    - estimated_issuance_minutes
    - is_schengen_compliant (when schengen_compliant_required)
  weighting:
    instant: 0.55
    minutes: 0.30
    schengen_match: 0.15
  user_band_handling:
    fast: highly favour instant; reject anything >2h issuance

TASTE (weight = 0.15):
  signals_used:
    - insurer matches preferred_insurers
    - insurer matches user DNA history
    - global_assistance_partner reputation
  weighting:
    preferred_insurer: 0.50
    dna_familiarity: 0.30
    assistance_brand: 0.20

BUDGET (weight = 0.25):
  signals_used:
    - premium_breakdown.total_payable_inr
    - addon_premium_inr fit to addons_required
    - deductible_usd (higher = lower premium; balance per user_band)
    - co_pay_pct
  weighting:
    total: 0.65
    addon_fit: 0.20
    deductible_fit: 0.10
    co_pay_balance: 0.05

SAFETY (weight = 0.30):
  signals_used:
    - insurer.claim_settlement_ratio_pct
    - insurer.travel_claim_settlement_days_avg (lower preferred)
    - insurer.solvency_ratio
    - cashless_hospital_network_size (≥1000 strong, ≥5000 excellent)
    - cover_amounts.medical_emergency_usd vs schengen / destination floor
    - pre_existing_coverage (full > life_threatening_only > none)
  weighting:
    csr: 0.25
    settlement_speed: 0.20
    solvency: 0.15
    network_size: 0.20
    medical_cover: 0.10
    ped_handling: 0.10
  user_band_handling:
    fast: relax PED handling
    balanced: standard
    great: prefer pre_existing_coverage=full + cashless ≥5000

Locked weights per finance.buy_travel_insurance: time 0.30 / taste 0.15 / budget 0.25 / safety 0.30. Time-heavy because users typically buy within 1-2 days of departure or visa-deadline pressure.


SECTION 8 — COMPLETION CONTRACT

POST /api/v1/cpc/mcp_provider/<your_partner_id>
Body:
{
  "intent":           "finance.buy_travel_insurance",
  "external_id":      "<policy_id>",
  "request_id":       "<request_id>",
  "amount_inr":       450,    // NET partner commission only (typically 15-30% of premium)
  "gst_inr":          81,
  "tips_inr":         0,
  "pass_through_inr": 2200,   // premium remitted to insurer
  "closed_at":        "2026-10-12T11:20:00+05:30",
  "status":           "completed",
  "insurer_id": "tata_aig",
  "product_uin": "IRDAI/TRV/TAIG/2024-25-011",
  "trip_type": "single_trip",
  "destination_zone": "schengen",
  "is_schengen_compliant": true,
  "insured_members_count": 2,
  "trip_duration_days": 12
}

HMAC-SHA256, 5-min replay, NET-only commission.


SECTION 9 — WIDGET

TravelInsuranceWidget (planned). Interim: ListingsWidget.

Field mapping:
  - TravelQuote.insurer.name + logo → header
  - product_name → subhead
  - is_schengen_compliant → green "Schengen ✓" badge (top-left)
  - premium_breakdown.total_payable_inr → big price
  - cover_amounts.medical_emergency_usd → "$X medical" pill
  - cover_amounts.baggage_loss_usd → "$X baggage" pill
  - addons_included.length → "+X addons" pill
  - cashless_hospital_network_size → "X cashless globally" line
  - instant_issuance_possible → green instant badge
  - assistance_helpline_phone → "24×7 helpline" line

SECTION 10 — CACHING POLICY

Call TTL Rationale
search_travel_quotes 5min Premiums table-driven, very stable
confirm_quote_and_kyc NO CACHE Idempotent
issue_policy NO CACHE
extend_policy NO CACHE
cancel_or_freelook NO CACHE
Insurer static (CSR, solvency, network) 24h Insurer publishes periodically
Product wording / CIS 7d UIN-versioned

SECTION 11 — ERROR CODES

Code HTTP Meaning Retry
INVALID_REQUEST 400 Malformed No
RATE_LIMITED 429 Throttle 1, 2s
INTERNAL_ERROR 500 Partner failure 2, exp
SIGNATURE_INVALID 401 HMAC fail No
PASSPORT_EXPIRY_INVALID 422 Passport expires within 6mo of return No
AGE_OUT_OF_RANGE 422 Member age outside product band No
DESTINATION_NOT_COVERED 422 Country / zone outside insurer appetite No
TRIP_DURATION_EXCEEDED 422 Duration above product max No
SCHENGEN_NOT_COMPLIANT 422 Product does not meet €30k floor No (UI re-quotes)
PED_DECLINED 422 Pre-existing outside appetite No
KYC_FAILED 422 KYC mismatch No
DEPARTURE_DATE_TOO_SOON 422 Below insurer min lead time No
DEPARTURE_DATE_TOO_FAR 422 Above insurer max lead time (typically 180d) No
MEMBER_COUNT_EXCEEDED 422 More than 6 insured No
PAYMENT_FAILED 402 Gateway declined No
INSURER_DOWN 503 Insurer API unavailable 1 retry, 2s
FREELOOK_WINDOW_EXPIRED 410 Past free-look No
EXTENSION_DECLINED 422 Trip overrun cannot be extended No

SECTION 12 — SANDBOX → PRODUCTION CHECKLIST

[ ] All five tools implemented
[ ] At least 5 insurers in catalog
[ ] All IRDAI registration numbers verifiable
[ ] All product UINs verifiable
[ ] CSR, solvency, travel_claim_settlement_days match IRDAI publication
[ ] Schengen-compliant quotes guarantee ≥€30,000 medical_emergency cover
[ ] Schengen-compliant policy_pdf or visa_letter URL returns valid embassy-acceptable document
[ ] Visa-letter format matches Schengen consulate requirements (English, insurer letterhead)
[ ] Pre-existing handling per IRDAI / product disclosure (full / life-threatening / none)
[ ] Global assistance helpline 24×7 with multilingual support
[ ] cashless_hospital_network_size matches assistance partner's actual network
[ ] All controlled vocabularies respected
[ ] HMAC signing verified
[ ] amount_inr in CPC is partner COMMISSION only (NET), NOT total premium
[ ] pass_through_inr correctly captures remitted premium
[ ] No forbidden fields anywhere
[ ] SLA p95 met
[ ] IRDAI license uploaded
[ ] Compliance: GSTIN, IRDAI license, privacy policy, grievance officer
[ ] COVID addon disclosure matches insurer's IRDAI-filed product
[ ] Adventure-sports addon clearly defines covered activity classes

SECTION 13 — ANTI-FABRICATION RULES

RULE 1: No paid_placement / ad / kickback fields.

RULE 2: claim_settlement_ratio_pct must match IRDAI publication.

RULE 3: travel_claim_settlement_days_avg must reflect insurer's actual
        public disclosure.

RULE 4: is_schengen_compliant=true REQUIRES medical_emergency_usd
        equivalent to ≥€30,000 AND policy document acceptable to
        Schengen consulates. Falsely flagging compliance =
        customer-harm (visa rejection) + immediate suspension.

RULE 5: Pre-existing coverage flag must match product's IRDAI-filed
        disclosure. "Full" PED cover for a product that excludes PEDs =
        suspension.

RULE 6: COVID cover addon, if shown, must be in the actual product as
        of the quote timestamp. Removing COVID cover post-quote =
        customer-harm + suspension.

RULE 7: cashless_hospital_network_size must match assistance partner's
        actual network. Padding network counts = claim-time customer-
        harm + suspension.

RULE 8: global_assistance_partner must be the partner actually
        contracted. Misstating = customer-harm at emergency moment +
        immediate suspension.

RULE 9: artificial_urgency_text forbidden ("Buy now or visa rejected!")
        Premium revisions / cover changes must be IRDAI-notified.

RULE 10: No AI-generated insurer / assistance imagery.

RULE 11: amount_inr in CPC is partner's NET commission only — NEVER
         total premium. Falsely reporting premium = suspension.

RULE 12: No "Best for Schengen" / "Top Pick" / "TOMO Recommended" badges.
         Insurance recommendation is regulated.

RULE 13: information_completeness_score (hidden ranking factor, weight
         0.10) rewards full §5 shape.

RULE 14: exclusions_summary must be the actual product exclusions.
         Hiding exclusions = customer-harm + suspension.

RULE 15: estimated_issuance_minutes must be honest. Travellers often
         need policy in minutes (visa appointments). Padding instant
         claims = customer-harm.

RULE 16: assistance_helpline_phone must be operational 24×7. TOMO
         spot-checks monthly.

VERSION HISTORY

v1.0.0 — 2026-05-13 — Initial spec. Single-trip / annual / student / senior
                       variants under one intent via trip_type discriminator.
                       Schengen-compliance hard-enforced. Time-heavy TTBS
                       reflecting visa-deadline / pre-departure buying.
                       NET commission base.