
A text message becomes a categorized Notion row
Send "spent $45 on lunch" in English or Russian and tap who it is for and the currency: a categorized row lands in Notion five steps later.
What runs automatically
Message parser
A regex and keyword pass turns a message like "spent $45 on lunch" into amount, type, category, date and notes, no model call involved. 22 categories are matched by keyword, checked in order, with no match falling into Other.
Confirm before it saves
The bot replies with buttons for who the transaction is for, then a currency choice, then a full preview of what it parsed. Nothing is written until one tap on Confirm.
A typed row in Notion
A confirmed transaction writes one row to a Notion database with a fixed schema: amount, type, category, date, notes, person and currency. Only Telegram user IDs on an explicit whitelist can trigger a write.
Built with Claude Code in 1 day
Logging a purchase meant opening an app and picking from menus.
A plain message becomes a categorized Notion row after one Confirm tap.
Under the hood
01Context
Tracking spending by hand means opening an app every time
Logging a purchase by hand means opening a separate app or spreadsheet, then picking a category, a currency and who it was for from a set of menus, for every coffee and every bill. That friction is exactly why a spending log tends to fall behind or stop after a few weeks. The bot logs a transaction from wherever it already gets mentioned: a short message in English or Russian.
02How it works
A message, three taps, a row in Notion
A message like 'spent $45 on lunch' or 'потратил 500 на обед' is the only typing involved. The bot replies with buttons for who it is for, then a currency choice between USD and EUR, then a preview of everything it parsed: amount, type, category, date and notes. Behind that reply, tools/parse_transaction.py matches the message against 22 categories by keyword, checked in order until one fits, and decides expense or income from words like 'spent' and 'paid' against 'received' and 'salary'.
03Constraints
Rule-based parsing, a whitelist, two ways to run it
Category detection is rule-based rather than a model call, so a message that matches no keyword lands in Other instead of a smart guess, and currency is limited to USD and EUR. The bot only answers Telegram user IDs on an explicit whitelist, and re-validates the person and currency server-side even though they arrive from button taps. The same code runs two ways: main.py for a local process, or modal_app.py on Modal, where credentials live as Modal secrets instead of a local .env file.
ANM SOLUTIONS / CONTACT US
Want something like this?
First 30-minute call is free. We scope it, you decide.



