Inspiration
I kept seeing the same story play out around us: someone gets a call saying their bank account is "blocked," a calm voice stays on the line, and a few minutes later their money is gone. These aren't careless people — they're rushed, scared, and walked through a payment with no space to think.
What struck us is that the phone already knows something is wrong. There's an active call. There's a scam SMS sitting in the inbox. The payee is a stranger. Every signal needed to catch the scam is right there — but no payment app connects those dots at the one moment that matters: when you tap Send. India loses thousands of crores a year to this exact pattern, and every UPI app treats the confirm button as its only job. I wanted to give that button a second job: to ask why you're paying.
What it does
WallUPI is a UPI payment app with an on-device fraud firewall built in. The instant you hit Send, it reads the situation around the payment — not just the amount — and scores how likely it is to be a scam.
It fuses five real-time signals:
- Who you're paying — new payee, or flagged by the community?
- Is the amount normal — far above your usual size?
- Are you on a call — especially with an unknown number?
- Any suspicious SMS — and does a flagged message name this exact payee?
- How you got here — a typed UPI ID, or a QR/link handoff?
These collapse into a single transparent risk score from $0$ to $100$, computed as a weighted blend of factor groups:
$$ \text{Risk} = w_{r}\,f_{\text{recipient}} + w_{u}\,f_{\text{user}} + w_{c}\,f_{\text{context}} + w_{rel}\,f_{\text{relationship}} $$
The score maps to four levels of friction:
| Score | Tier | Response |
|---|---|---|
| 0–49 | Safe | Goes through instantly |
| 50–79 | Soft | Warning popup with reasons |
| 80–94 | Strong | Full-screen warning + checkbox |
| 95–100 | Critical | 10-second forced lock, then confirm |
That 10-second lock is the whole point: even a brief, forced pause breaks the pressure a scammer builds.
How I built it
- Frontend: Flutter (Dart), Android-first, with native Android bridges I wrote for SMS access and live call-state detection.
- On-device AI (two layers): a hand-crafted Dart rule engine for obvious patterns, plus TinyBERT running locally via TensorFlow Lite that classifies each SMS into fraud categories (phishing, fake KYC, UPI fraud, social engineering).
- Cloud fallback: when TinyBERT is uncertain, a sanitized snippet (names and numbers stripped) goes to Gemini 1.5 Flash for a second opinion in plain English.
- Backend: Flask (Python 3) REST endpoints for scoring, SMS analysis, and an explainable factor breakdown; SQLite (Flask-SQLAlchemy) for recipient reputation and community spam flags; an ngrok static tunnel for live demos.
- Risk engine: a deterministic, weighted multi-factor scorer that runs on the backend and is mirrored locally so scoring is instant even offline.
All three AI layers run in parallel and fuse into one score, with every contributing factor shown to the user.
Challenges I ran into
- On-device ML inside Flutter. Getting TinyBERT quantized into TFLite and running fast on-device through Flutter's native channels — with the tokenizer and vocab bundled — took real plumbing.
- Native Android permissions. SMS and call-state are sensitive, OEM-fragmented APIs; building reliable native bridges and handling the permission UX cleanly was fiddly.
- Privacy without losing signal. I had to design the sanitization step so the cloud call still gets useful context while never letting personal data leave the phone.
- Determinism. A risk score that protects people has to be explainable and reproducible — so I made the engine fully deterministic and the local mirror exactly match the backend, instead of a black box.
- Demoing fraud without real money. I built a complete admin/demo mode that simulates calls, unknown callers, and pre-loaded scam SMS so judges can trigger every tier on command — proving the detection is real even though settlement is mocked.
Accomplishments that I am proud of
- A fully working end-to-end app where the entire fraud engine is real, not faked.
- Genuinely on-device scam detection — TinyBERT + rules run with no connection, and sensitive data never leaves the phone.
- The signal I think no one else has: correlating a scam SMS to the very payee you're about to pay, surfaced right on the Send Money screen.
- A transparent 0–100 score with a human-readable reason for every decision — and the 10-second critical lock that turns a behavioral insight into a real intervention.
What I learned
- The intervention that matters isn't a better warning — it's time. Scam victims are rushed, so a forced pause does more than any red text.
- Privacy and protection aren't in tension if you do inference on-device; that's also the only design that's adoptable at national scale.
- A lot about the Indian fraud landscape — UPI is free by regulation, so the value lives in the safety layer, and regulators (RBI/NPCI) are actively pushing toward proactive scam prevention.
- Practically: how to ship real ML to the edge, wrangle native Android, and keep a risk system explainable.
What's next for WallUPI
- Phishing-Origin Payment Detection — analyze where a payment request came from (WhatsApp/SMS links, fake KYC pages), classify the source URL with TinyBERT, and warn/delay/block before transfer.
- Offline UPI (IVR-style) — a 123PAY-inspired flow that keeps the full fraud layer running with no internet.
- A real-user pilot to prove our risk score correlates with reported fraud.
- Going to market two ways: WallUPI as the safest UPI app, and as a security layer I license to other apps, banks, PSPs, and eventually NPCI.
Don't just confirm the payment. Question it.
Log in or sign up for Devpost to join the conversation.