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.
● LIVEv1.0.0pay.add_money_to_wallet

pay.add_money_to_wallet — Full Intent Specification

INTENT NAMESPACE: pay
INTENT NAME:      add_money_to_wallet
FULL ID:          pay.add_money_to_wallet
VERSION:          v1.0.0
STATUS:           live
TTBS WEIGHTS:     time 0.35 · taste 0.10 · budget 0.35 · safety 0.20
LAST UPDATED:     2026-05-14

Load funds into a third-party wallet (FASTag, transit metro card, gaming/streaming app wallet, food-delivery wallet, RBI-licensed PPI like Paytm/PhonePe Wallet, etc.) from the user's bank account via UPI / netbanking / card. Distinct from pay.send_money_upi because: (a) destination is not a person but a regulated PPI/closed-loop wallet; (b) the wallet operator must hold an RBI PPI license (or be a sub-issuer of one); (c) certain wallets (FASTag, metro) have hardware/account-state side-effects (tag balance, gate-clearance state) — TOMO must reflect those; (d) max wallet balance under RBI PPI rules is regulated (₹2L full-KYC PPI, ₹10k small-PPI); (e) reload fees vary by partner and funding rail — TOMO must surface the all-in cost.


1. NATURAL LANGUAGE COVERAGE

Classifies IN

  • "add ₹500 to my FASTag"
  • "recharge FASTag HDFC ₹2000"
  • "load ₹1000 metro card Hyderabad"
  • "add money to Paytm wallet ₹500"
  • "top up PhonePe wallet"
  • "recharge Swiggy Money ₹300"
  • "load BookMyShow wallet ₹1000"
  • "add ₹2000 to Amazon Pay"
  • "load my Ola Money"
  • "add cash to ONDC wallet"

Classifies OUT — borderline NO

  • "send money to Rohit" → pay.send_money_upi
  • "pay electricity bill" → pay.utility_bill_pay
  • "buy mobile recharge" → pay.utility_bill_pay (telecom is treated as utility v1)
  • "add forex to my forex card" → travel.book_forex
  • "deposit to savings account" → out of scope (banking, not wallet)
  • "buy giftcard" → adjacent — out of v1 (gift card has its own state semantics)

MULTI-INTENT TRIGGERS

  • "recharge FASTag and book outstation cab" → pay.add_money_to_wallet + mobility.book_outstation_package
  • "top up metro card before tomorrow's commute" → pay.add_money_to_wallet + mobility.book_recurring_commute
  • "load Swiggy Money and order biryani" → pay.add_money_to_wallet + food.order_delivery

2. INPUT — TOMO → PROVIDER

{
  "intent":          "pay.add_money_to_wallet",
  "intent_version":  "v1.0.0",
  "request_id":      "req_wt_3m8x_2026-05-14T11:08:00Z",
  "user_session_id": "anon_user_token_or_uid",

  "wallet": {
    "category":    "fastag",
    "operator":    "HDFC FASTag",
    "account_ref": "tag_hdfc_xxxx7421",
    "kyc_band":    "full"
  },

  "amount_inr":   2000,

  "source_instrument": {
    "type":        "upi",
    "vpa":         "keerthi@hdfcbank",
    "fallbacks":   ["netbanking", "debit_card"]
  },

  "schedule": {
    "mode":         "now",
    "modes_allowed": ["now", "auto_when_low"],
    "auto_when_low_threshold_inr": 200,
    "auto_topup_amount_inr": 1000
  },

  "user_constants": {
    "vehicle_rc_optional": "TS09EZ1234",
    "tag_class_optional":  "VC4"
  }
}

Field rules

  • wallet.category ENUM strict. Each category maps to a known set of valid operator values; mismatch → ERR_OPERATOR_CATEGORY_MISMATCH.
  • amount_inr integer (INR_INTEGER); decimals rejected.
  • wallet.kyc_band ∈ {full, small, unknown} drives RBI PPI ceiling: full ≤ ₹2L balance; small ≤ ₹10k balance; unknown → block.
  • auto_when_low_threshold_inr requires UPI Autopay mandate (RBI's recurring framework); created out-of-band, referenced by mandate_id.

3. PROVIDER TOOLS

The wallet-load MCP server (pay-wallet-mcp) exposes exactly these tools. Each operator-side wallet is RBI-licensed PPI (or a closed-loop sub-issuer); TOMO is routing only.

wallet.resolve_account

Confirms account/tag exists and is active. Returns current balance + KYC band.

{
  "tool": "wallet.resolve_account",
  "input": {"category": "fastag", "operator": "HDFC FASTag", "account_ref": "tag_hdfc_xxxx7421"},
  "output": {
    "valid":          true,
    "vehicle_rc_match": "TS09EZ1234",
    "current_balance_inr": 120,
    "kyc_band":       "full",
    "tag_class":      "VC4",
    "tag_blacklist_flag": false,
    "low_balance_flag": true
  }
}

wallet.load

Initiates a load. Hands off to user's UPI app / netbanking page / card 3DS. Returns load_id.

wallet.status

Polls the load state.

wallet.set_autopay_mandate

Creates UPI Autopay mandate for auto-when-low. Mandate is between user's bank and wallet operator — TOMO is referenced as the initiator only.

wallet.cancel_autopay

Revokes the mandate.

wallet.refund

Refunds an unsuccessful or partial load (rare — only when destination credit failed but source debited).


4. RESPONSE SHAPE — PROVIDER → TOMO

{
  "intent": "pay.add_money_to_wallet",
  "request_id": "req_wt_3m8x_2026-05-14T11:08:00Z",
  "wallet": {
    "category":     "fastag",
    "operator":     "HDFC FASTag",
    "account_ref":  "tag_hdfc_xxxx7421",
    "current_balance_inr": 120,
    "kyc_band":     "full",
    "vehicle_rc":   "TS09EZ1234",
    "low_balance_flag": true,
    "tag_blacklist_flag": false
  },
  "options": [
    {
      "tier": "OK",
      "amount_inr":  500,
      "funding_rail": "upi",
      "fee_inr":     0,
      "credit_eta_seconds": 30,
      "ppi_license_no": "PPI-MD-DPSS.CO.PD.No.512/02.14.006/2016-17",
      "post_load_balance_estimate_inr": 620,
      "tier_reason": "minimum top-up — fastest, free"
    },
    {
      "tier": "GOOD",
      "amount_inr":  2000,
      "funding_rail": "upi",
      "fee_inr":     0,
      "credit_eta_seconds": 30,
      "ppi_license_no": "PPI-MD-DPSS.CO.PD.No.512/02.14.006/2016-17",
      "post_load_balance_estimate_inr": 2120,
      "tier_reason": "balanced — covers ~10 toll crossings, free"
    },
    {
      "tier": "GREAT",
      "amount_inr":  2000,
      "funding_rail": "upi",
      "fee_inr":     0,
      "credit_eta_seconds": 30,
      "ppi_license_no": "PPI-MD-DPSS.CO.PD.No.512/02.14.006/2016-17",
      "autopay_mandate_inr_per_trigger": 1000,
      "autopay_trigger_balance_inr": 200,
      "post_load_balance_estimate_inr": 2120,
      "tier_reason": "auto-top-up at ₹200, never run out again"
    }
  ],
  "kyc_disclosure": {
    "band":          "full",
    "ceiling_inr":   200000,
    "current_balance_inr": 120,
    "post_load_balance_inr": 2120,
    "headroom_inr":  197880
  }
}

Field rules

  • ppi_license_no MUST appear for every option (RBI license). Missing → drop option.
  • credit_eta_seconds is the operator-attested post-debit credit time. Display as plain English ("usually under 30s").
  • fee_inr ALWAYS shown — never folded silently into amount_inr.
  • tag_blacklist_flag: true → block load and surface remediation (NHAI dispute/RC sync) inline.

5. CONTROLLED VOCABULARIES

wallet.category

fastag · metro_card · ppi_general · food_app_wallet · mobility_app_wallet · entertainment_app_wallet · ecom_app_wallet · gaming_app_wallet

funding_rail

upi · netbanking · debit_card · credit_card

kyc_band

full · small · unknown

schedule.mode

now · auto_when_low

All STRICT ENUM. Anything else → ERR_VOCAB.


6. TTBS DIMENSIONS

TIME (weight 0.35)

  • credit_eta_seconds (smaller = better)
  • Funding rail latency — UPI ~ instant, netbanking ~ minutes, card 3DS variable
  • Operator's published reliability SLA
  • TIME score = 1 − min(1, credit_eta_seconds / 300)

TASTE (weight 0.10)

  • Operator brand familiarity to user (from on-device usage history)
  • App-side post-load confirmation clarity
  • Friction at funding rail (single tap vs 3DS interruption)
  • TASTE score = brand_familiar × rail_friction_inv

BUDGET (weight 0.35)

  • fee_inr (zero ideal)
  • Hidden cross-rail markup (e.g. credit-card surcharge on some operators)
  • Auto-topup amount sized rationally vs use pattern
  • BUDGET score = 1 − fee_pct − hidden_markup_pct

SAFETY (weight 0.20)

  • Operator RBI PPI license cache age ≤ 14 days
  • Tag/account blacklist state false
  • KYC band compatible with new balance
  • TOMO never holds funds — wallet operator + funding rail PSP are both regulated
  • SAFETY score = ppi_license_valid × not_blacklisted × kyc_compatible × rail_psp_compliant

HARD FILTERS (apply before scoring)

  1. Operator must hold valid RBI PPI license (or be a verified sub-issuer of one).
  2. Account/tag must resolve as valid.
  3. Tag/account not blacklisted.
  4. Post-load balance must not breach KYC ceiling.
  5. auto_when_low mode requires existing or just-created Autopay mandate.

7. COMPLETION CONTRACT

Success criteria

  1. wallet.resolve_account returns valid: true, balance + KYC band.
  2. UPI/netbanking/card debit succeeds at user's bank.
  3. Wallet operator credits balance within credit_eta_seconds.
  4. wallet.status confirms state: credited.
  5. Push notification to user with old balance → new balance.
  6. CPC webhook fires.

CPC webhook (HMAC-SHA256, 5-min replay window)

{
  "event": "pay.add_money_to_wallet.completed",
  "intent_id": "pay.add_money_to_wallet",
  "request_id": "req_wt_3m8x_2026-05-14T11:08:00Z",
  "load_id":    "WLD7K2X9",
  "wallet": {
    "category": "fastag",
    "operator": "HDFC FASTag",
    "account_ref": "tag_hdfc_xxxx7421"
  },
  "amount_inr":            2000,
  "fee_inr":               0,
  "pass_through_inr":      2000,
  "tomo_commission_base_inr": 0,
  "tomo_commission_inr":   0,
  "funding_rail":          "upi",
  "credit_eta_actual_seconds": 22,
  "ppi_license_no":        "PPI-MD-DPSS.CO.PD.No.512/02.14.006/2016-17",
  "completed_at_iso":      "2026-05-14T11:08:34+05:30",
  "signature_hmac_sha666": "REPLACE_BEFORE_PROD",
  "signature_hmac_sha256": "…"
}

Note: most operators absorb the load themselves and pay TOMO a fixed per-load referral (₹2–₹10 depending on category), NOT a percent of amount_inr. The tomo_commission_base_inr is therefore the per-load fee where contracted, otherwise 0. Aligns with COMMISSION BASE = NET — TOMO never books the load amount itself as revenue.

Failure cases

  • debit_succeeded_credit_failed → operator-side dispute auto-opened; user gets refund SLA banner (T+1 working day).
  • tag_blacklisted → block + remediation steps.
  • kyc_ceiling_breached → block + ask user to upgrade KYC or load smaller.
  • mandate_creation_failed → fall back to single-shot now.

8. WIDGET — UOE → UI

{
  "widget": "WalletLoadWidget",
  "header": {
    "title": "HDFC FASTag · TS09EZ1234",
    "balance_strip": "Current ₹120 · low balance · ~1 toll crossing left",
    "kyc_strip":    "Full KYC · headroom ₹1,97,880 of ₹2,00,000"
  },
  "regions": {
    "region_1_intelligence": ["tag active", "RC matches vehicle on file", "no blacklist flag", "PPI license verified 2d ago"],
    "region_2_summary":      "Add ₹X to your FASTag — UPI, free, ~30s credit",
    "region_3_visual":       "tag_artwork_url (operator-supplied, signed)",
    "region_4_now_pin":      "Pay ₹2,000 via UPI now",
    "region_5_tomo_choices": [
      {"tier": "OK",    "label": "₹500 · 1-tap UPI · ~30s",                       "reason": "fastest minimum"},
      {"tier": "GOOD",  "label": "₹2,000 · 1-tap UPI · covers ~10 tolls",         "reason": "balanced"},
      {"tier": "GREAT", "label": "₹2,000 + auto top-up below ₹200",                "reason": "set and forget"}
    ]
  },
  "footer_disclosures": [
    "TOMO never holds your money. Funds go from your bank straight to the operator's RBI-licensed wallet.",
    "UPI loads are free — fees only apply on credit-card top-ups (we'll show the number before you confirm).",
    "You can cancel auto top-up anytime in your bank's UPI Autopay screen."
  ]
}

UI invariants:

  • Current balance + operator license disclosed at top.
  • Fee shown plainly (even if zero).
  • Autopay mandate explicit consent screen before mandate creation.

9. CACHING POLICY

  • Operator PPI license: cache 14 days at registry layer.
  • wallet.resolve_account: cache 60s on-device; re-resolve before any load.
  • Current balance: never stale beyond 60s on the load surface.
  • Past loads (read-only ledger): cache 90 days on-device, encrypted.
  • Autopay mandate state: subscribed via PSP webhook; no polling cache.

10. ERROR CODES

Code Meaning UI surface
ERR_OPERATOR_CATEGORY_MISMATCH operator not in category "We don't recognize this combo" + valid list
ERR_ACCOUNT_NOT_FOUND resolve_account valid: false "Tag/account not found — re-enter?"
ERR_TAG_BLACKLISTED tag_blacklist_flag true Plain explainer + remediation link
ERR_KYC_CEILING_BREACH post-load > PPI ceiling "Load would exceed RBI's ₹X ceiling — load smaller or upgrade KYC"
ERR_FUNDING_RAIL_DOWN UPI/netbanking/card rail unavailable Fallback rail prompt
ERR_DEBIT_OK_CREDIT_FAIL source debited, dest not credited Auto-dispute banner with refund SLA
ERR_MANDATE_CREATION_FAILED UPI Autopay rejected by user's bank Fall back to single-shot
ERR_LICENSE_STALE operator PPI license cache > 14d Drop option before showing user
ERR_AMOUNT_BELOW_MIN amount < operator min Show min + adjust
ERR_AMOUNT_ABOVE_MAX_PER_TXN per-load cap exceeded Show cap + adjust

11. SANDBOX → PRODUCTION CHECKLIST

  • Sandbox wallet.resolve_account returns realistic balance + blacklist flag.
  • Sandbox UPI debit OK + credit OK happy path.
  • Sandbox UPI debit OK + credit FAIL flow generates refund SLA.
  • Sandbox KYC ceiling enforced at ₹2L (full) and ₹10k (small).
  • Sandbox tag_blacklist_flag blocks load.
  • Sandbox Autopay mandate creation tested end-to-end across at least 3 banks.
  • Sandbox CPC webhook signed HMAC-SHA256 (fix any placeholder fields).
  • Production operator PPI licenses pulled weekly from RBI master directory.
  • Production rate-limit: max 10 loads per user per hour per operator.
  • Production fraud watch — multi-account-same-card pattern flagged.
  • Production refund SLA T+1 measured on real disputed loads.
  • Production push notification on credit confirmation tested across iOS / Android.

12. ANTI-FABRICATION RULES

  • NO paid_placement / editor_pick on wallet operators — operator is chosen by user, not ranked.
  • NO synthetic current_balance — always operator-fresh.
  • NO hidden surcharge folded into amount_inr — fee is a separate line, always.
  • NO "instant credit guarantee" — show credit_eta_seconds as estimate, with explicit "usually" qualifier.
  • NO auto-recommend an amount higher than user's typical pattern — top-up suggestion stays user-pattern-aware.
  • NO bundling load with promo offers from the operator — keeps the payment surface clean.
  • NO marketing language ("smart wallet", "intelligent top-up") — boring plain UI is the doctrine.
  • NO showing post-load balance as confirmed until operator credit webhook fires.
  • NO Autopay mandate creation without explicit consent screen — never auto-opt-in.
  • NO TOMO-issued referral nudge ("invite a friend to load") on the payment surface.

13. REGULATORY FRAMING

  • RBI Master Direction on PPIs (DPSS.CO.PD.No.1064/02.14.006/2017-18, as amended) governs every wallet operator. Full-KYC PPI: ₹2L balance. Small-PPI: ₹10k balance + ₹10k/month load.
  • NHAI FASTag is regulated under MoRTH + RBI PPI. Each issuer (HDFC/ICICI/SBI/Paytm/etc.) holds its own PPI license.
  • Metro cards in major cities (DMRC/HMRL/CMRL/BMRC) are closed-loop PPIs under state transit authority.
  • NPCI UPI Autopay governs auto_when_low mandate creation. Mandate is bank-to-operator; TOMO is initiator only.
  • DPDPA 2023 — account_ref / vehicle_rc / tag_class are personal data; encrypted on-device + at partner, never at TOMO.
  • PMLA 2002 — operator (not TOMO) is the PMLA reporter for suspicious loads.
  • TOMO does NOT operate any wallet itself, does NOT hold any PPI license, does NOT carry any custody risk.