Intent Spec — finance.apply_credit_card
FULL ID: finance.apply_credit_card
VERSION: v1.0.0
STATUS: draft
LAST UPDATED: 2026-05-13
DOMAIN: finance
PRIMARY AGENT: FinanceAgent
TTBS WEIGHTS: time=0.20 taste=0.25 budget=0.30 safety=0.25
User applies for a credit card from a bank or co-branded NBFC. Covers eligibility check (soft pull), card discovery across issuers, KYC, instant virtual / physical card issuance, mandate setup, rewards / cashback / lounge / fuel-surcharge benefits, and joining-fee handling. Distinct from credit lines / personal loans.
Partner exemplars: BankBazaar, Paisabazaar, OneCard, Slice (partnership), HDFC Bank, ICICI Bank, SBI Card, Axis Bank, IDFC First, AmEx India, Standard Chartered, RBL Bank, IndusInd.
SECTION 1 — INTENT IDENTITY
User wants to apply for a credit card. Distinct from:
finance.apply_personal_loan— term loan, not revolving- BNPL / pay-later — v1.1+
finance.apply_bnpl - Co-branded charge cards (Diners) — same intent
- Corporate cards — v1.1+
- Secured credit card (FD-backed) — same intent; user specifies
card_class=secured_fd_backed - Forex card — v1.1+
- Add-on card — v1.1+
Single intent per card application. Comparing across issuers happens internally in §4 (TOMO fans out).
SECTION 2 — NATURAL LANGUAGE COVERAGE
CLASSIFIES IN
- "Best travel credit card"
- "Cashback credit card for online shopping"
- "Lifetime free credit card"
- "Credit card for first-time user no credit history"
- "Premium card with lounge access"
- "Fuel surcharge waiver card"
- "Amazon Pay credit card"
- "Credit card for self-employed"
- "Secured credit card against fixed deposit"
- "AmEx Membership Rewards card"
CLASSIFIES OUT — BORDERLINE NO
- "Personal loan" →
finance.apply_personal_loan - "BNPL / Pay Later" → v1.1+
- "Forex card" → v1.1+
- "Increase my credit limit" → v1.1+
- "What's my CIBIL?" → v1.1+
- "Credit card EMI conversion" — non-transactional within an existing card
MULTI-INTENT TRIGGERS
- "Credit card + insurance" →
finance.apply_credit_card+finance.buy_term_insurance - "Travel card + flight + hotel booking" → composite mission with
travel.book_flight+travel.book_hotel - "Cashback card + grocery shopping setup" →
finance.apply_credit_card(no second intent — TOMO surfaces card-stacking insights post-issuance)
SECTION 3 — INPUT (TOMO → PROVIDER)
{
"intent": "finance.apply_credit_card",
"request_id": "req_01J9Z...",
"user_locale": "en-IN",
"user_currency": "INR",
"user_location": { "lat": 17.4475, "lng": 78.3563, "city": "Hyderabad", "pincode": "500032" },
"applicant": {
"first_name": "Rakesh", "last_name": "Kumar",
"date_of_birth": "1990-04-18",
"gender": "male",
"pan_last4": "5678",
"mobile_e164": "+919876543210",
"email": "rakesh@example.com",
"current_address_pincode": "500032",
"marital_status": "married",
"education": "graduate",
"employment": {
"type": "salaried_corporate",
"industry": "information_technology",
"company_name": "Acme Pvt Ltd",
"company_category": "listed_or_psu",
"designation": "Senior Engineer",
"years_at_current_employer": 3,
"net_monthly_income_inr": 125000,
"gross_annual_income_inr": 1800000
},
"existing_relationships": {
"has_savings_account_with_issuer": [], // list of issuer IDs (relationship discount)
"has_existing_credit_card": true,
"existing_card_oldest_age_months": 60,
"credit_cards_count": 2
},
"obligations": {
"existing_emi_monthly_inr": 22000,
"credit_cards_outstanding_inr": 35000,
"consent_for_credit_bureau_pull": true,
"consent_for_aa_aggregator_pull": true
}
},
"card_preferences": {
"primary_use_case": "travel_lounge", // STRICT ENUM §6
"card_class_preference": "premium", // STRICT ENUM §6
"preferred_networks": ["visa_signature", "mastercard_world"], // STRICT ENUM array §6
"preferred_issuers": [],
"joining_fee_tolerance_inr": 5000,
"annual_fee_tolerance_inr": 5000,
"want_lifetime_free": false,
"want_lounge_access": true,
"want_fuel_surcharge_waiver": true,
"want_movie_offers": false,
"want_milestone_benefits": true,
"want_emi_conversion_facility": true,
"secured_fd_amount_inr": null // non-null only when card_class_preference=secured_fd_backed
},
"ttbs_user_band": {
"time": "balanced",
"taste": "great",
"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.apply_credit_card |
applicant.pan_last4 |
string | REQUIRED, 4 digits | Full PAN at KYC |
applicant.mobile_e164 |
string | REQUIRED, E.164 | OTP-verified by issuer |
applicant.employment.type |
enum | REQUIRED, STRICT ENUM §6 | |
applicant.employment.net_monthly_income_inr |
int | REQUIRED, INR_INTEGER | Drives card-class eligibility |
applicant.existing_relationships.has_existing_credit_card |
bool | REQUIRED | Drives no-credit-history product surfacing |
applicant.obligations.consent_for_credit_bureau_pull |
bool | REQUIRED, value MUST be true | |
card_preferences.primary_use_case |
enum | REQUIRED, STRICT ENUM §6 | Drives rewards-mix ranking |
card_preferences.card_class_preference |
enum | REQUIRED, STRICT ENUM §6 | starter / standard / premium / super_premium / secured_fd_backed |
card_preferences.secured_fd_amount_inr |
int | REQUIRED nullable | Non-null required when card_class_preference=secured_fd_backed |
Anti-fabrication preamble: Reward rates and milestones must reflect issuer's current published terms. Hidden devaluations (silently lowering reward rate post-issuance) violate consumer law. Joining + annual fees must match T&C exactly. No misrepresentation of complimentary lounge / movie / fuel benefits.
SECTION 4 — PROVIDER TOOLS
Tool 1: search_card_offers
PURPOSE: Up to 12 card offers matching profile + preferences (soft-pull-based)
SLA: p50 ≤ 800ms, p95 ≤ 2500ms, p99 ≤ 5000ms
RATE LIMIT: 60 req/min
IDEMPOTENCY: request_id; 10min cache
RETRY: 1 on 429, 2 on 5xx
Tool 2: submit_card_application
PURPOSE: Hard-pull + KYC + employment / income verification
SLA: p50 ≤ 2500ms, p95 ≤ 7000ms, p99 ≤ 15000ms
RATE LIMIT: 30 req/min
IDEMPOTENCY: request_id
RETRY: No retry
Tool 3: issue_virtual_card
PURPOSE: Instant virtual card credentials for online use
SLA: p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT: 30 req/min
IDEMPOTENCY: application_id
RETRY: No retry
Tool 4: schedule_physical_delivery
PURPOSE: Schedule physical card delivery
SLA: p50 ≤ 1200ms, p95 ≤ 3500ms
RATE LIMIT: 30 req/min
IDEMPOTENCY: application_id
RETRY: 1 on 5xx
Tool 5: cancel_pre_issuance
PURPOSE: Cancel application before card is dispatched
SLA: p50 ≤ 1500ms, p95 ≤ 4000ms
RATE LIMIT: 45 req/min
IDEMPOTENCY: application_id
RETRY: 1 on 5xx
SECTION 5 — RESPONSE SHAPE
CardOffer
CardOffer:
offer_id: { type: string, constraint: REQUIRED, opaque }
issuer:
issuer_id: { type: string, constraint: REQUIRED }
name: { type: string, constraint: REQUIRED }
rbi_registration_number: { type: string, constraint: REQUIRED }
card:
card_id: { type: string, constraint: REQUIRED }
card_name: { type: string, constraint: REQUIRED, semantics: "Marketed product name" }
card_class: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
network: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
network_tier_label: { type: string, constraint: REQUIRED, semantics: "Visa Signature / Mastercard World / etc." }
is_co_branded: { type: boolean, constraint: REQUIRED }
co_brand_partner: { type: string, constraint: REQUIRED nullable }
image_url: { type: string, constraint: REQUIRED, HTTPS URL }
is_pre_approved: { type: boolean, constraint: REQUIRED }
estimated_credit_limit_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
estimated_cash_limit_pct: { type: float, constraint: REQUIRED, 0-100, semantics: "% of credit limit as cash-advance limit" }
fees:
joining_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
annual_fee_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
gst_on_fees_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
is_lifetime_free: { type: boolean, constraint: REQUIRED }
joining_fee_waiver_condition: { type: string, constraint: REQUIRED, semantics: "Plain-language condition or empty if none" }
annual_fee_waiver_condition: { type: string, constraint: REQUIRED, semantics: "Plain-language condition or empty if none" }
interest:
apr_finance_charge_pct_monthly: { type: float, constraint: REQUIRED, 0-5 }
apr_finance_charge_pct_annual: { type: float, constraint: REQUIRED, 0-50 }
interest_free_days_max: { type: int, constraint: REQUIRED, 18-55 }
cash_advance_interest_pct_monthly: { type: float, constraint: REQUIRED, 0-5 }
charges:
late_payment_charge_inr_min: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
late_payment_charge_inr_max: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
over_limit_charge_pct: { type: float, constraint: REQUIRED, 0-10 }
cash_advance_charge_pct: { type: float, constraint: REQUIRED, 0-5 }
forex_markup_pct: { type: float, constraint: REQUIRED, 0-5 }
fuel_surcharge_pct: { type: float, constraint: REQUIRED, 0-5 }
fuel_surcharge_waiver_cap_monthly_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
rewards:
type:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [cashback, points, miles, mixed]
base_rate_pct: { type: float, constraint: REQUIRED, 0-10, semantics: "Base reward rate on default spends" }
accelerated_categories:
type: array<AcceleratedCategory>
constraint: REQUIRED, may be empty
shape:
category: { type: enum, constraint: REQUIRED, STRICT ENUM §6 }
rate_pct: { type: float, constraint: REQUIRED, 0-15 }
monthly_cap_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
point_value_inr_per_point: { type: float, constraint: REQUIRED, ≥0, semantics: "0 for cashback / miles" }
capping_rule: { type: string, constraint: REQUIRED }
milestone_benefits:
type: array<Milestone>
constraint: REQUIRED, may be empty
shape:
milestone_inr_per_year: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
reward_label: { type: string, constraint: REQUIRED }
reward_value_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
complimentary_benefits:
domestic_lounge_visits_per_year: { type: int, constraint: REQUIRED, ≥0 }
international_lounge_visits_per_year: { type: int, constraint: REQUIRED, ≥0 }
priority_pass: { type: boolean, constraint: REQUIRED }
movie_buy_one_get_one: { type: boolean, constraint: REQUIRED }
movie_offer_cap_monthly_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
golf_access: { type: boolean, constraint: REQUIRED }
concierge_24x7: { type: boolean, constraint: REQUIRED }
travel_insurance_included_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
purchase_protection_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
fraud_liability_protection: { type: boolean, constraint: REQUIRED }
emi_conversion:
available: { type: boolean, constraint: REQUIRED }
min_transaction_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
interest_rate_pct: { type: float, constraint: REQUIRED, 0-25 }
tenure_months_available: { type: array<int>, constraint: REQUIRED, may NOT be empty }
issuance:
virtual_card_instant: { type: boolean, constraint: REQUIRED }
physical_card_estimated_days: { type: int, constraint: REQUIRED, 1-30 }
instant_pin_setup: { type: boolean, constraint: REQUIRED }
validity_minutes: { type: int, constraint: REQUIRED, 60-86400 }
hard_pull_required_on_acceptance: { type: boolean, constraint: REQUIRED }
most_important_terms_url: { type: string, constraint: REQUIRED, HTTPS URL, semantics: "RBI-mandated MITC document" }
card_agreement_url: { type: string, constraint: REQUIRED, HTTPS URL }
rewards_terms_url: { type: string, constraint: REQUIRED, HTTPS URL }
partner_reference:
source: { type: string, constraint: REQUIRED }
deeplink: { type: string, constraint: REQUIRED, HTTPS URL }
ApplicationResult
ApplicationResult:
application_id: { type: string, constraint: REQUIRED }
offer_id: { type: string, constraint: REQUIRED }
status:
type: enum
constraint: REQUIRED, STRICT ENUM §6
values: [approved_at_offered_terms, approved_revised_limit, conditional_approval_docs_pending, in_underwriting, declined_credit, declined_policy, declined_income, withdrawn_by_applicant]
revised_credit_limit_inr: { type: int, constraint: REQUIRED nullable, INR_INTEGER, ≥0 }
decision_reason_code:
type: enum
constraint: REQUIRED nullable, STRICT ENUM §6
values: [credit_score_low, dpd_recent, foir_exceeded, income_unverified, employer_uncovered, bureau_thin_file, fraud_flag, policy_decline_other]
decision_valid_until: { type: string, constraint: REQUIRED, ISO_DATETIME }
documents_pending: { type: array<string>, constraint: REQUIRED, may be empty }
kyc_status: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [verified, video_kyc_pending, manual_pending, failed] }
VirtualCardCredentials
VirtualCardCredentials:
application_id: { type: string, constraint: REQUIRED }
virtual_card_token: { type: string, constraint: REQUIRED, semantics: "Tokenised reference; never raw PAN" }
card_holder_name: { type: string, constraint: REQUIRED }
expiry_yyyymm: { type: string, constraint: REQUIRED, semantics: "MM/YY" }
credit_limit_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
available_limit_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
cash_limit_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
is_activated: { type: boolean, constraint: REQUIRED }
network_token_provisionable: { type: boolean, constraint: REQUIRED, semantics: "Eligible to add to GPay / Apple Pay" }
issued_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
PhysicalDeliverySchedule
PhysicalDeliverySchedule:
application_id: { type: string, constraint: REQUIRED }
delivery_id: { type: string, constraint: REQUIRED }
delivery_partner: { type: string, constraint: REQUIRED, semantics: "Courier name" }
tracking_number: { type: string, constraint: REQUIRED nullable }
estimated_delivery_date: { type: string, constraint: REQUIRED, ISO_DATE }
delivery_address: { type: string, constraint: REQUIRED }
contact_phone: { type: string, constraint: REQUIRED, E.164 }
ovd_required_at_delivery: { type: boolean, constraint: REQUIRED, semantics: "Officially valid document for OTP-less hand-over" }
CancellationResult
CancellationResult:
application_id: { type: string, constraint: REQUIRED }
cancelled_at: { type: string, constraint: REQUIRED, ISO_DATETIME }
status: { type: enum, constraint: REQUIRED, STRICT ENUM §6, values: [cancelled_pre_issuance, cancellation_failed_post_issuance] }
refund_amount_inr: { type: int, constraint: REQUIRED, INR_INTEGER, ≥0 }
refund_eta_days: { type: int, constraint: REQUIRED, 0-30 }
FORBIDDEN FIELDS
paid_placement_score,ad_bid,sponsored_rank,kickback_amountartificial_urgency_text("Free joining expires tonight!" without basis)ai_generated_photofor issuer / card imagery (real card image only)inflated_reward_rate(must match issuer published)hidden_devaluation_clause(silent reward-rate cuts forbidden in disclosures)mandatory_insurance_bundleeditor_recommended,tomo_pick,best_for_travelforex_markup_below_disclosed_floorover_inflated_credit_limit(display must be lender's actual eligibility, not aspirational)
SECTION 6 — CONTROLLED VOCABULARIES
applicant.education: [class_10, class_12, diploma, graduate, postgraduate, doctorate]
applicant.marital_status: [single, married, divorced, widowed]
applicant.employment.type:
values:
salaried_corporate, salaried_government, salaried_psu,
self_employed_professional, self_employed_business, retired
applicant.employment.industry:
values:
information_technology, financial_services, manufacturing, retail,
healthcare, education, government, defence, hospitality, real_estate,
media_entertainment, agriculture, logistics, energy, telecom, e_commerce,
consulting, legal_services, other
applicant.employment.company_category:
values: [listed_or_psu, private_ltd_top_tier, private_ltd_other, partnership_or_llp, proprietorship]
card_preferences.primary_use_case:
values:
travel_lounge: "Frequent travel, lounges, miles / hotel points"
cashback_general: "Everyday spends with flat / category cashback"
online_shopping: "Amazon / Flipkart / e-commerce co-branded"
grocery_dining: "Grocery + dining accelerated rewards"
fuel_commute: "Fuel surcharge waiver + commute spends"
movie_entertainment: "Movies + dining benefits"
business_self_employed: "Higher limits + GST capture + travel"
no_credit_history: "Starter / secured card for first-timers"
card_preferences.card_class_preference / card_class:
values:
starter: "Entry-level; income ₹15k-25k/mo; ₹0-500 joining"
standard: "Mid-tier; income ₹25k-75k/mo; ₹500-2000 joining"
premium: "Premium; income ₹75k-2L/mo; ₹2k-10k joining"
super_premium: "Super-premium; income ≥₹2L/mo; ₹10k+ joining (Infinia, Magnus etc.)"
secured_fd_backed: "FD-backed; for thin-file / no-credit-history users"
card_preferences.preferred_networks / network:
values:
visa_classic, visa_signature, visa_infinite,
mastercard_standard, mastercard_titanium, mastercard_world, mastercard_world_elite,
rupay_classic, rupay_platinum, rupay_select,
amex_green, amex_gold, amex_platinum, diners_club_black
rewards.type: [cashback, points, miles, mixed]
rewards.accelerated_categories[].category:
values:
dining, grocery, fuel, online_shopping, travel_air, travel_hotel,
movies, utility_bills, education, e_wallets, insurance,
upi_p2m, rent, government_payments, healthcare, telecom
ApplicationResult.status:
values: [approved_at_offered_terms, approved_revised_limit, conditional_approval_docs_pending, in_underwriting, declined_credit, declined_policy, declined_income, withdrawn_by_applicant]
decision_reason_code:
values: [credit_score_low, dpd_recent, foir_exceeded, income_unverified, employer_uncovered, bureau_thin_file, fraud_flag, policy_decline_other]
kyc_status: [verified, video_kyc_pending, manual_pending, failed]
CancellationResult.status: [cancelled_pre_issuance, cancellation_failed_post_issuance]
SECTION 7 — TTBS DIMENSIONS
TIME (weight = 0.20):
signals_used:
- is_pre_approved
- virtual_card_instant
- physical_card_estimated_days
- instant_pin_setup
weighting:
pre_approved: 0.40
virtual_instant: 0.30
physical_speed: 0.20
instant_pin: 0.10
TASTE (weight = 0.25):
signals_used:
- card_class matches user's preference exactly
- network matches preferred_networks
- is_co_branded matches user DNA (e.g. heavy Amazon spender + Amazon card)
- issuer matches existing_relationships.has_savings_account_with_issuer
- primary_use_case match to accelerated_categories
weighting:
use_case_match: 0.35
network_match: 0.25
co_brand_dna: 0.20
existing_relationship: 0.15
class_match: 0.05
BUDGET (weight = 0.30):
signals_used:
- is_lifetime_free
- joining_fee_inr vs tolerance
- annual_fee_inr vs tolerance
- annual_fee_waiver_condition realistic for user's spending profile
- apr_finance_charge_pct_monthly
- rewards.base_rate_pct + accelerated effective return
- milestone_benefits net value vs spend assumption
weighting:
fee_fit: 0.40
effective_rewards_return: 0.45
apr: 0.10
milestone_value: 0.05
user_band_handling:
ok: lifetime free preferred; lowest annual
good: balanced fee vs reward value
great: fee-insensitive; max reward + benefits dominate
SAFETY (weight = 0.25):
signals_used:
- issuer.rbi_registration_number active
- fraud_liability_protection
- complimentary_benefits.purchase_protection_inr
- most_important_terms_url present and current
- issuer's regulator-grievance handling reputation
- network tier reflects actual benefit eligibility (no fake "World" labelling)
weighting:
issuer_regulatory: 0.40
fraud_protection: 0.25
purchase_protection: 0.15
documents_compliant: 0.10
network_labelling_accurate: 0.10
user_band_handling:
fast: relaxed
balanced: standard
great: prefer issuers with strongest fraud-resolution track record
Locked weights per finance.apply_credit_card: time 0.20 / taste 0.25 / budget 0.30 / safety 0.25. Taste is uplifted (0.25 vs 0.10 for loans) because cards are deeply preference-driven (network, co-brand, lounges, miles).
SECTION 8 — COMPLETION CONTRACT
POST /api/v1/cpc/mcp_provider/<your_partner_id>
Body:
{
"intent": "finance.apply_credit_card",
"external_id": "<application_id>",
"request_id": "<request_id>",
"amount_inr": 1800, // NET partner / DSA commission per activated card (typically ₹500-3000)
"gst_inr": 324,
"tips_inr": 0,
"pass_through_inr": 0, // No money passes through — credit instrument, not disbursement
"closed_at": "2026-05-18T11:20:00+05:30",
"status": "completed",
"issuer_id": "hdfc_bank",
"card_id": "millennia",
"card_class": "standard",
"is_pre_approved": false,
"credit_limit_inr": 200000
}
Important: amount_inr = partner / DSA commission only. Credit cards have NO pass-through (instrument, not money flow). TOMO charges 10% × commission only.
HMAC-SHA256, 5-min replay, NET-only commission.
SECTION 9 — WIDGET
CreditCardWidget (planned). Interim: comparison ListingsWidget.
Field mapping:
- CardOffer.card.image_url → card visual
- card.card_name → title
- issuer.name → subhead
- network_tier_label → eyebrow ("Visa Signature")
- is_lifetime_free → green "LTF" badge
- joining_fee_inr / annual_fee_inr → fee line
- rewards.base_rate_pct + top accelerated category → reward line
- complimentary_benefits.domestic_lounge_visits_per_year → "X lounges" pill
- milestone_benefits → "₹X / year milestones" pill
- is_pre_approved → green badge
- virtual_card_instant → "Instant card" badge
- most_important_terms_url → "View MITC" link (mandatory)
SECTION 10 — CACHING POLICY
| Call | TTL | Rationale |
|---|---|---|
| search_card_offers | 10min | Stable for short window |
| submit_card_application | NO CACHE | — |
| issue_virtual_card | NO CACHE | — |
| schedule_physical_delivery | NO CACHE | — |
| cancel_pre_issuance | NO CACHE | — |
| Issuer / card static (image, terms, benefits) | 24h | Issuer publishes updates |
| MITC / Agreement / Rewards URLs | 7d | 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 |
CREDIT_BUREAU_CONSENT_MISSING |
422 | No consent | No |
THIN_BUREAU_FILE |
422 | Insufficient credit history | No |
AGE_OUT_OF_RANGE |
422 | Outside issuer age band | No |
INCOME_BELOW_THRESHOLD |
422 | Below issuer floor | No |
EMPLOYER_NOT_COVERED |
422 | Outside approved employer list | No |
EXISTING_DUPLICATE_CARD |
422 | Active card of same product exists | No |
KYC_FAILED |
422 | KYC mismatch | No |
SECURED_FD_REQUIRED |
422 | Secured card without FD reference | No |
ADDRESS_VERIFICATION_FAILED |
422 | Cannot verify delivery address | No |
VIRTUAL_CARD_NOT_SUPPORTED |
422 | Product doesn't offer virtual card | No |
ISSUER_DOWN |
503 | Issuer API unavailable | 1 retry, 2s |
OFFER_EXPIRED |
410 | Past offer validity | No |
APPLICATION_BLOCKED_FRAUD_FLAG |
422 | Fraud flag at issuer | No |
SECTION 12 — SANDBOX → PRODUCTION CHECKLIST
[ ] All five tools implemented
[ ] At least 6 issuers in catalog (mix of banks + co-branded)
[ ] All RBI registration numbers verifiable
[ ] Reward rates match issuer's current published terms
[ ] Accelerated category rates accurate per latest schedule
[ ] Joining + annual fees match T&C exactly
[ ] Annual fee waiver conditions accurate (spend thresholds verifiable)
[ ] APR finance charge (monthly + annual) accurate
[ ] Interest-free days accurate (18-55 typical)
[ ] forex_markup_pct accurate; min 1.5% for RBI compliance
[ ] fuel_surcharge_pct + waiver_cap accurate
[ ] Lounge benefits accurate (domestic + international counts)
[ ] Milestone benefits accurate (₹ thresholds + rewards)
[ ] Insurance / purchase protection accurate
[ ] EMI conversion rates + tenures accurate
[ ] most_important_terms_url returns RBI-mandated MITC
[ ] All controlled vocabularies respected
[ ] HMAC signing verified
[ ] amount_inr in CPC is partner COMMISSION only (NET)
[ ] pass_through_inr is ZERO (instrument, not money flow)
[ ] No forbidden fields anywhere
[ ] No "Top Pick" / "Best for X" badges
[ ] No fake "World" / "Signature" tier labelling for cards not actually that tier
[ ] SLA p95 met
[ ] DSA / connector arrangement with each issuer uploaded
[ ] Compliance: GSTIN, DSA agreements, privacy policy, grievance officer
[ ] Customer support: working hours + RBI ombudsman escalation
[ ] DPDP Act compliance: explicit consent for bureau + KYC
SECTION 13 — ANTI-FABRICATION RULES
RULE 1: No paid_placement / ad / kickback fields. Credit card DSA
commissions vary widely (₹500-3000+ per card). Bias risk is
material. TOMO audits monthly.
RULE 2: rewards.base_rate_pct, accelerated_categories rates, and
milestone_benefits MUST match issuer's current published
terms. Inflating to win on Budget axis = customer-harm +
immediate suspension.
RULE 3: rewards.point_value_inr_per_point must reflect realistic
redemption value. Quoting "1 point = ₹1" when actual
airline-mile redemption is ₹0.25 = customer-harm.
RULE 4: capping_rule must accurately describe per-category and
overall monthly caps. Misstating = customer-harm.
RULE 5: most_important_terms_url MUST be the issuer's RBI-mandated
MITC document for the specific card variant. Marketing pages
in this slot = regulatory breach + suspension.
RULE 6: Annual fee waiver conditions must be accurate. If actual
waiver requires ₹5L annual spend but partner states ₹3L,
customer trusts and renews = suspension.
RULE 7: Lounge access counts must match issuer's actual schedule
(often differs by network tier; misstating = customer-harm
at airport).
RULE 8: forex_markup_pct must accurately reflect issuer's actual
markup including DCC handling. Hiding markup = customer-
harm + suspension.
RULE 9: estimated_credit_limit_inr cannot be aspirational. Display
must be based on actual eligibility derived from soft pull.
Bait-and-switch = suspension.
RULE 10: network_tier_label must reflect the ACTUAL network tier of
the card. Labelling a Mastercard Titanium as "Mastercard
World" to win taste signals = network-violation + suspension.
RULE 11: artificial_urgency_text forbidden ("Free joining last day!"
without verifiable promotion calendar).
RULE 12: No AI-generated card / issuer imagery. Real card images
only, per issuer brand-use agreement.
RULE 13: amount_inr in CPC is partner / DSA commission only — NEVER
pass-through (which is always zero for cards).
RULE 14: No "Top Pick" / "Best for Travel" / "Recommended" badges.
RULE 15: information_completeness_score (hidden ranking factor,
weight 0.10) rewards full §5 shape.
RULE 16: For co-branded cards, co_brand_partner must be the actual
co-branding partner (not a similar-name imposter).
RULE 17: Joining / annual fee in §5 must match what issuer charges
at activation. Surprise fees = immediate suspension.
RULE 18: complimentary_benefits flags (priority_pass / golf /
concierge / movie / travel insurance) must match issuer's
actual disclosure for this card variant. Padding =
customer-harm + suspension.
RULE 19: For secured / FD-backed cards, secured_fd_amount_inr must
match the FD lien value. Misrepresenting lien amount =
consumer-law breach + suspension.
RULE 20: emi_conversion.interest_rate_pct must match issuer's
published EMI rate. EMI conversion fee + rate disclosure
is RBI-mandated.
VERSION HISTORY
v1.0.0 — 2026-05-13 — Initial spec. Credit card application across
starter / standard / premium / super_premium /
secured. Taste-uplifted TTBS (network +
co-brand + use-case fit). NET commission base.
MITC enforced. No reward / fee / benefit
fabrication.