The Android companion app for PayNey β your effortless expense tracker.
PayNey Capture turns your phone into an automatic transaction sensor. It reads your bank/UPI SMS alerts and payment-app notifications the moment they arrive and forwards them to your PayNey account, so every expense lands in your tracker without a single manual entry. Snap a photo of a paper receipt and it pulls out the amount, merchant, and date for you too.
Think of it as the eyes and ears of PayNey on your device: the web app is where you review, categorize, and analyze; Capture is what feeds it in real time.
π Web app: payney.vercel.app Β β’Β Download the APK: latest release
Manually logging every coffee, cab, and grocery run is the reason most expense trackers get abandoned after a week. In India, though, almost every spend already announces itself: a bank SMS ("Rs. 450 debited...") or a UPI app notification from GPay, PhonePe, or Paytm. PayNey Capture listens for exactly those signals, filters out everything that isn't a real transaction, and streams the rest to your PayNey backend β so your ledger stays complete with zero effort.
- Automatic SMS capture β Listens for incoming bank/UPI SMS and forwards matching messages to PayNey in the background.
- Notification capture β Reads notifications from allowlisted payment apps (Google Pay, PhonePe, Paytm, CRED) and forwards transaction alerts.
- Receipt scanning β Photograph a paper receipt and the backend extracts the amount, merchant, date, and a suggested category for you to review, edit, and confirm into your PayNey queue.
- Accurate transaction dates β Each capture is stamped with when the event actually happened (SMS delivery time, notification post time), not when it was uploaded β so a capture that waited in the offline queue is still dated correctly.
- Privacy-first allowlisting β Only messages from a known list of bank sender IDs and payment-app packages ever leave the device. Arbitrary personal SMS and notifications are silently ignored.
- Durable offline outbox β Captures made while offline (or during a server outage) are queued locally and retried automatically when connectivity returns, so a transaction is never lost.
- Duplicate suppression β Apps that re-post the same notification won't create duplicate captures; repeats within a short window are dropped on-device.
- Secure device pairing β Link the app to your PayNey account with a one-time pairing code from the web app; the resulting device token is kept in encrypted storage.
- Live status dashboard β Permission state, capture on/off, queued-item count, and the time of your last successful sync, all at a glance β plus a manual sync button to flush the queue on demand.
βββββββββββββββββββββββ ββββββββββββββββββββββββ βββββββββββββββββββββ
β Bank / UPI SMS ββββββββΆ β β β β
βββββββββββββββββββββββ€ β PayNey Capture ββββββββΆ β PayNey Backend β
β Payment-app ββββββββΆ β (allowlist + β HTTPS β /api/... β
β notifications β β offline outbox) β β β
βββββββββββββββββββββββ€ β β β Web expense β
β Scanned receipt ββββββββΆ β β β tracker β
βββββββββββββββββββββββ ββββββββββββββββββββββββ βββββββββββββββββββββ
- Pair the device once using a code from the PayNey web app
(
POST /api/device/pairβ device token). SmsReceiverandNotificationCaptureServiceobserve incoming events and check each one againstAllowList.- Matches are handed to a single
CaptureRepository, which posts them toPOST /api/transactions/ingestβ or queues them in the local outbox and retries later if the network is down. - Receipts are uploaded to
POST /api/transactions/receiptfor field extraction, then confirmed viaPOST /api/transactions/receipt/confirm.
| Endpoint | Method | Purpose |
|---|---|---|
/api/device/pair |
POST | Exchange a pairing code for a device token |
/api/transactions/ingest |
POST | Ingest a captured SMS / notification |
/api/transactions/receipt |
POST (multipart) | Extract fields from a receipt image |
/api/transactions/receipt/confirm |
POST | Persist a reviewed receipt to the review queue |
- Language: Kotlin 2.1
- UI: Jetpack Compose + Material 3
- Architecture: MVVM (ViewModel + Compose state), Navigation Compose
- Networking: Retrofit 2 + OkHttp,
kotlinx.serializationJSON - Concurrency: Kotlin Coroutines
- Security: AndroidX Security Crypto (encrypted token storage)
- Capture:
BroadcastReceiver(SMS) +NotificationListenerService - Min SDK: 26 (Android 8.0) Β β’Β Target/Compile SDK: 36
Grab the signed APK from the latest release and install it on any device running Android 8.0 (API 26) or newer. You'll need to allow installs from your browser/file manager the first time, since the app is distributed outside the Play Store.
Release builds always target the deployed backend at payney.vercel.app β no configuration required. Just install, open, and pair.
- Android Studio (latest stable)
- JDK 17
- An Android device or emulator running API 26+
- A running PayNey backend (local or deployed)
-
Clone the repo
git clone https://github.com/othzer/payney-capture.git cd payney-capture -
Point the app at your backend. Copy the example and edit as needed:
cp local.properties.example local.properties
- Emulator (default): no changes needed β it uses
http://10.0.2.2:3000. - Physical device: run
adb reverse tcp:3000 tcp:3000and setPAYNEY_API_BASE_URL=http://127.0.0.1:3000, or point it at your deployed backend URL.
- Emulator (default): no changes needed β it uses
-
Build & run from Android Studio, or from the command line:
./gradlew installDebug
Debug vs. release URLs. Debug builds use
PAYNEY_API_BASE_URL(defaulthttp://10.0.2.2:3000) so you can develop against a local backend. Release builds ignore that and usePAYNEY_RELEASE_API_BASE_URL(defaulthttps://payney.vercel.app) instead, so a distributed APK can never accidentally ship pointing at localhost.
- Open PayNey Capture and enter the pairing code shown in the PayNey web app.
- Grant SMS permission and enable Notification access (Settings β Notification access) from the in-app Status screen.
- Leave capture on β transactions now flow to PayNey automatically.
- Tap Scan a receipt to photograph a bill and confirm the extracted details.
PayNey Capture is deliberately conservative about what leaves your device:
| Permission | Why it's needed |
|---|---|
RECEIVE_SMS / READ_SMS |
Detect incoming bank/UPI transaction SMS |
| Notification access | Read notifications from allowlisted payment apps |
CAMERA |
Photograph receipts for scanning |
INTERNET / ACCESS_NETWORK_STATE |
Send captures and retry the offline queue |
Only messages matching the bank sender IDs and payment-app packages defined in
AllowList are ever transmitted. Everything else β personal texts, unrelated
notifications β is discarded on-device and never sent anywhere. The device token
is kept in encrypted storage, and allowBackup is disabled.
app/src/main/java/com/otzrlabs/payney/capture/
βββ capture/ # SMS receiver, notification listener, allowlist
β βββ AllowList.kt
β βββ NotificationCaptureService.kt
β βββ SmsReceiver.kt
βββ data/ # Repository, outbox, prefs, token store
β βββ CaptureRepository.kt
β βββ CaptureOutbox.kt
β βββ CapturePrefs.kt
β βββ TokenStore.kt
β βββ network/ # Retrofit service + models
βββ ui/ # Compose screens (pair, status, scan receipt)
β βββ pair/ status/ receipt/
β βββ brand/ nav/ theme/
βββ util/ # Camera capture helper
Contributions are always welcome.
- Star the repository
- Fork the repository
- Create a feature branch
- Commit your changes
- Open a Pull Request
If you found it useful,
please consider giving the repository a β.
It helps more than you think.
Proprietary β Β© OtzrLabs. All rights reserved.