How it works
When your bank sends a push notification — “SGD 45.50 spent at Grab” — Vantage reads it in the background, extracts the amount, merchant, and card details, categorises it, and logs it to your database. All automatically, within seconds of the transaction.The notification listener
Vantage uses a native KotlinNotificationListenerService that runs independently of the Flutter app. Even if the app is killed, the listener keeps running and queues notifications in SharedPreferences for the next app launch.
Key properties:
- Always-on: survives app kills, device restarts (registered for
RECEIVE_BOOT_COMPLETED) - Dedup: SHA-256 hash of
packageName + text + timestamp_minute— prevents duplicate entries from notification updates - 5-day window: hashes are stored for 5 days, then cleaned up
- Queue: if Flutter is not running, notifications are queued and drained on next launch
Regex parsing
Each supported banking app has a set ofRegExp patterns that match its specific notification format. The parser tries each pattern in order and returns the first successful match.
amount— the transaction amountmerchant— merchant name (cleaned of trailing punctuation)card— last 4 digits of card (when available)cur— explicit currency code (e.g.SGDin “for SGD 45.50”)
Merchant categorisation
After parsing, Vantage maps the merchant name to a spend category:- Exact match against 500+ merchant mappings (
lib/core/constants/merchants.dart) - Substring match — case-insensitive contains check
- AI fallback — Claude Haiku infers category from merchant name
- Uncategorised — if all fail, user can manually correct
Transaction types
| Type | Description |
|---|---|
debit | Card spend or bank debit |
credit | Refund, payment received |
trade_buy | Stock/crypto purchase (brokerage apps) |
trade_sell | Stock/crypto sale (brokerage apps) |