Overview
This page provides practical examples and code snippets for common use cases with the Monzoh library. Each example includes complete, runnable code with explanations.Basic Examples
Account Overview Dashboard
Create a comprehensive overview of all your Monzo accounts:Copy
from monzoh import MonzoClient, MonzoError
from datetime import datetime
def create_dashboard():
"""Create a comprehensive account dashboard."""
try:
client = MonzoClient()
# Verify authentication
whoami = client.whoami()
print(f"🔐 Authenticated as: {whoami.user_id}")
print(f"📅 Dashboard generated: {datetime.now(tz=datetime.timezone.utc).strftime('%Y-%m-%d %H:%M:%S')}")
print("\n" + "="*60)
# Get all accounts
accounts = client.accounts.list()
print(f"📱 Found {len(accounts)} accounts")
total_balance = 0
total_spent_today = 0
for i, account in enumerate(accounts, 1):
if account.closed:
continue
print(f"\n{i}. {account.description}")
print("-" * len(f"{i}. {account.description}"))
# Get balance
balance = account.get_balance()
balance_gbp = balance.balance
spent_today_gbp = balance.spend_today
total_balance += balance_gbp
total_spent_today += spent_today_gbp
# Status indicator
if balance_gbp < 10:
status = "⚠️ Low Balance"
elif balance_gbp > 1000:
status = "💚 Healthy"
else:
status = "💛 Normal"
print(f" Balance: £{balance_gbp:.2f} {status}")
print(f" Spent Today: £{spent_today_gbp:.2f}")
print(f" Total Balance: £{balance.total_balance / 100:.2f}")
print(f" Account Type: {account.type}")
# Get recent transactions
transactions = account.list_transactions(limit=3)
if transactions:
print(" Recent Transactions:")
for txn in transactions:
amount = txn.amount / 100
emoji = "💸" if amount < 0 else "💰"
print(f" {emoji} {txn.description}: £{amount:.2f}")
# Summary
print(f"\n{'SUMMARY'}")
print("="*60)
print(f"💰 Total Balance: £{total_balance:.2f}")
print(f"💸 Total Spent Today: £{total_spent_today:.2f}")
print(f"📊 Net Position: £{total_balance - total_spent_today:.2f}")
# Get pots summary
pots = client.pots.list()
if pots:
total_savings = sum(pot.balance for pot in pots) / 100
print(f"🐷 Savings in Pots: £{total_savings:.2f}")
print(f"💎 Total Assets: £{total_balance + total_savings:.2f}")
except MonzoError as e:
print(f"❌ Error: {e}")
if __name__ == "__main__":
create_dashboard()
Transaction Analysis
Analyze spending patterns and categorize transactions:Copy
from monzoh import MonzoClient
from collections import defaultdict, Counter
from datetime import datetime, timedelta
def analyze_spending(days=30):
"""Analyze spending patterns over the last N days."""
client = MonzoClient()
# Get accounts
accounts = client.accounts.list()
current_account = next(
(acc for acc in accounts if acc.type == "uk_retail"),
accounts[0]
)
print(f"📊 Spending Analysis for {current_account.description}")
print(f"📅 Last {days} days")
print("="*50)
# Get transactions
since = datetime.now(tz=datetime.timezone.utc) - timedelta(days=days)
transactions = current_account.list_transactions(
since=since.isoformat(),
limit=200
)
# Analyze spending (negative amounts)
spending_transactions = [t for t in transactions if t.amount < 0]
if not spending_transactions:
print("No spending transactions found.")
return
# Category analysis
categories = Counter()
total_spent = 0
merchant_spending = defaultdict(int)
daily_spending = defaultdict(int)
for txn in spending_transactions:
amount = abs(txn.amount) / 100 # Convert to positive pounds
total_spent += amount
# Category
if txn.category:
categories[txn.category] += amount
else:
categories['Uncategorized'] += amount
# Merchant
if txn.merchant and txn.merchant.name:
merchant_spending[txn.merchant.name] += amount
# Daily spending
txn_date = datetime.fromisoformat(txn.created.replace('Z', '+00:00')).date()
daily_spending[txn_date] += amount
print(f"💸 Total Spent: £{total_spent:.2f}")
print(f"🔢 Number of Transactions: {len(spending_transactions)}")
print(f"📊 Average per Transaction: £{total_spent / len(spending_transactions):.2f}")
print(f"📅 Average per Day: £{total_spent / days:.2f}")
# Top categories
print(f"\n🏷️ Top Spending Categories:")
for category, amount in categories.most_common(5):
percentage = (amount / total_spent) * 100
print(f" {category}: £{amount:.2f} ({percentage:.1f}%)")
# Top merchants
if merchant_spending:
print(f"\n🏪 Top Merchants:")
for merchant, amount in sorted(
merchant_spending.items(),
key=lambda x: x[1],
reverse=True
)[:5]:
percentage = (amount / total_spent) * 100
print(f" {merchant}: £{amount:.2f} ({percentage:.1f}%)")
# Spending trends
if len(daily_spending) > 7:
recent_week = sum(
amount for date, amount in daily_spending.items()
if date >= (datetime.now(tz=datetime.timezone.utc).date() - timedelta(days=7))
)
previous_week = sum(
amount for date, amount in daily_spending.items()
if (datetime.now(tz=datetime.timezone.utc).date() - timedelta(days=14)) <= date < (datetime.now(tz=datetime.timezone.utc).date() - timedelta(days=7))
)
if previous_week > 0:
change = ((recent_week - previous_week) / previous_week) * 100
trend = "📈" if change > 0 else "📉"
print(f"\n{trend} Week-over-week change: {change:+.1f}%")
print(f" This week: £{recent_week:.2f}")
print(f" Last week: £{previous_week:.2f}")
if __name__ == "__main__":
analyze_spending(30)
Savings Automation
Automate savings transfers and pot management:Copy
from monzoh import MonzoClient, MonzoError
from decimal import Decimal
class SavingsAutomator:
def __init__(self):
self.client = MonzoClient()
self.accounts = self.client.accounts.list()
self.current_account = next(
(acc for acc in self.accounts if acc.type == "uk_retail"),
self.accounts[0]
)
def round_up_savings(self, limit_pounds=50):
"""Implement round-up savings by analyzing recent transactions."""
print("🔄 Analyzing transactions for round-up savings...")
# Get recent transactions
transactions = self.current_account.list_transactions(limit=50)
# Calculate round-ups for spending transactions
total_roundup = 0
roundup_transactions = []
for txn in transactions:
if txn.amount < 0: # Spending transaction
amount_pounds = abs(txn.amount) / 100
rounded_amount = int(amount_pounds) + 1
roundup = rounded_amount - amount_pounds
if roundup < 1.0: # Only if there's actually something to round up
total_roundup += roundup
roundup_transactions.append({
'description': txn.description,
'amount': amount_pounds,
'roundup': roundup
})
print(f"💰 Found £{total_roundup:.2f} in potential round-up savings")
print(f"📊 From {len(roundup_transactions)} transactions")
# Apply limit
if total_roundup > limit_pounds:
total_roundup = limit_pounds
print(f"⚠️ Limited to £{limit_pounds:.2f} maximum")
if total_roundup > 0:
return self.transfer_to_savings(
total_roundup,
f"Round-up savings from {len(roundup_transactions)} transactions"
)
else:
print("No round-up savings available")
return False
def percentage_savings(self, percentage=10, min_amount=5):
"""Save a percentage of income transactions."""
print(f"📈 Implementing {percentage}% savings rule...")
# Get recent income transactions (positive amounts)
transactions = self.current_account.list_transactions(limit=20)
income_transactions = [t for t in transactions if t.amount > 0]
if not income_transactions:
print("No recent income transactions found")
return False
total_savings = 0
for txn in income_transactions:
income_amount = txn.amount / 100
savings_amount = income_amount * (percentage / 100)
if savings_amount >= min_amount:
total_savings += savings_amount
print(f"💸 {txn.description}: £{income_amount:.2f} → Save £{savings_amount:.2f}")
if total_savings > 0:
return self.transfer_to_savings(
total_savings,
f"{percentage}% savings from recent income"
)
else:
print(f"No income transactions above £{min_amount:.2f} minimum found")
return False
def transfer_to_savings(self, amount_pounds, reason):
"""Transfer money to the first available savings pot."""
pots = self.client.pots.list()
savings_pots = [p for p in pots if not p.deleted]
if not savings_pots:
print("❌ No savings pots available")
return False
# Use first available pot
target_pot = savings_pots[0]
amount_pence = int(amount_pounds * 100)
try:
result = target_pot.deposit(amount=amount_pence)
print(f"✅ Transferred £{amount_pounds:.2f} to '{target_pot.name}'")
print(f"📝 Reason: {reason}")
# Show updated balance
updated_balance = self.current_account.get_balance()
print(f"💳 New account balance: £{updated_balance.balance / 100:.2f}")
return True
except MonzoError as e:
print(f"❌ Failed to transfer to savings: {e}")
return False
def savings_goal_progress(self):
"""Show progress towards savings goals."""
pots = self.client.pots.list()
if not pots:
print("No savings pots found")
return
print("🎯 Savings Goals Progress:")
print("="*40)
total_saved = 0
total_goals = 0
for pot in pots:
if pot.deleted:
continue
balance = pot.balance / 100
total_saved += balance
print(f"\n🐷 {pot.name}")
print(f" Balance: £{balance:.2f}")
if pot.goal and pot.goal > 0:
goal = pot.goal / 100
total_goals += goal
progress = (balance / goal) * 100
# Progress bar
bar_length = 20
filled = int((progress / 100) * bar_length)
bar = "█" * filled + "░" * (bar_length - filled)
print(f" Goal: £{goal:.2f}")
print(f" Progress: {progress:.1f}% [{bar}]")
if progress >= 100:
print(" 🎉 Goal achieved!")
else:
remaining = goal - balance
print(f" Remaining: £{remaining:.2f}")
else:
print(" No goal set")
print(f"\n📊 Overall Summary:")
print(f" Total Saved: £{total_saved:.2f}")
if total_goals > 0:
overall_progress = (total_saved / total_goals) * 100
print(f" Total Goals: £{total_goals:.2f}")
print(f" Overall Progress: {overall_progress:.1f}%")
def main():
"""Main automation routine."""
automator = SavingsAutomator()
print("🤖 Monzo Savings Automator")
print("="*40)
# Show current savings status
automator.savings_goal_progress()
print("\n🔄 Running automation rules...")
# Try round-up savings
automator.round_up_savings(limit_pounds=25)
# Try percentage savings
automator.percentage_savings(percentage=5, min_amount=10)
if __name__ == "__main__":
main()
Advanced Examples
Webhook Event Handler
Set up webhook handling for real-time transaction notifications:Copy
from fastapi import FastAPI, Request, HTTPException
from monzoh import MonzoClient
import json
from datetime import datetime
app = FastAPI(title="Monzo Webhook Handler")
@app.post("/monzo/webhook")
async def handle_monzo_webhook(request: Request):
"""Handle incoming Monzo webhook events."""
# Get the raw body
body = await request.body()
# Parse the webhook data
try:
data = json.loads(body.decode())
except json.JSONDecodeError:
raise HTTPException(status_code=400, detail="Invalid JSON")
# Handle different event types
event_type = data.get("type")
if event_type == "transaction.created":
await handle_transaction_created(data["data"])
elif event_type == "account_balance.updated":
await handle_balance_updated(data["data"])
else:
print(f"Unhandled event type: {event_type}")
return {"status": "ok"}
async def handle_transaction_created(transaction_data):
"""Handle new transaction events."""
amount = transaction_data["amount"] / 100
description = transaction_data["description"]
merchant = transaction_data.get("merchant", {})
merchant_name = merchant.get("name", "Unknown") if merchant else "Unknown"
print(f"💳 New transaction: {description}")
print(f" Amount: £{amount:.2f}")
print(f" Merchant: {merchant_name}")
print(f" Time: {datetime.now(tz=datetime.timezone.utc)}")
# Custom logic for transaction events
if amount < -50: # Large spending
print("⚠️ Large transaction alert!")
# Could send email, SMS, or push notification
if "coffee" in description.lower() or (merchant_name and "coffee" in merchant_name.lower()):
print("☕ Coffee purchase detected!")
# Track coffee spending, etc.
async def handle_balance_updated(balance_data):
"""Handle balance update events."""
balance = balance_data["balance"] / 100
print(f"💰 Balance updated: £{balance:.2f}")
# Custom logic for balance events
if balance < 10:
print("⚠️ Low balance alert!")
# Could trigger automatic savings withdrawal or send alert
# Register webhook with Monzo
def register_webhook():
"""Register this webhook endpoint with Monzo."""
client = MonzoClient()
# Get the first account
accounts = client.accounts.list()
account_id = accounts[0].id
# Register webhook
webhook_url = "https://your-domain.com/monzo/webhook" # Update with your URL
try:
webhook = client.webhooks.create(
account_id=account_id,
url=webhook_url
)
print(f"✅ Webhook registered: {webhook.id}")
return webhook
except Exception as e:
print(f"❌ Failed to register webhook: {e}")
return None
if __name__ == "__main__":
import uvicorn
# Register webhook on startup
register_webhook()
# Start the server
uvicorn.run(app, host="0.0.0.0", port=8000)
Receipt and Attachment Manager
Manage receipts and attachments for transactions:Copy
from monzoh import MonzoClient, MonzoError
from pathlib import Path
import mimetypes
from datetime import datetime
class ReceiptManager:
def __init__(self):
self.client = MonzoClient()
def add_receipt_to_transaction(self, transaction, receipt_data):
"""Add detailed receipt information to a transaction using OO-style method."""
try:
receipt = transaction.create_receipt(**receipt_data)
print(f"✅ Receipt added to transaction {transaction.id}")
return receipt
except MonzoError as e:
print(f"❌ Failed to add receipt: {e}")
return None
def upload_receipt_image(self, transaction, image_path):
"""Upload a receipt image and attach it to a transaction using OO-style method."""
image_file = Path(image_path)
if not image_file.exists():
print(f"❌ File not found: {image_path}")
return None
# Determine content type
content_type, _ = mimetypes.guess_type(str(image_file))
if not content_type or not content_type.startswith('image/'):
print(f"❌ Invalid image file: {image_path}")
return None
try:
# Upload the attachment using OO-style method
with open(image_file, 'rb') as f:
attachment = transaction.upload_attachment(
image_file.name,
file_type=content_type,
file_data=f.read()
)
print(f"✅ Receipt image uploaded: {attachment.id}")
print(f" File: {image_file.name}")
print(f" Size: {image_file.stat().st_size} bytes")
return attachment
except MonzoError as e:
print(f"❌ Failed to upload receipt: {e}")
return None
def create_detailed_receipt(self, transaction, receipt_info):
"""Create a detailed receipt with line items using OO-style method."""
# Example receipt structure
receipt_data = {
"merchant_name": receipt_info.get("merchant_name", ""),
"merchant_address": receipt_info.get("address", ""),
"merchant_phone": receipt_info.get("phone", ""),
"merchant_email": receipt_info.get("email", ""),
"transaction_number": receipt_info.get("transaction_number", ""),
"total_amount": receipt_info.get("total_amount", 0),
"currency": receipt_info.get("currency", "GBP"),
"items": receipt_info.get("items", []),
"taxes": receipt_info.get("taxes", [])
}
return self.add_receipt_to_transaction(transaction, receipt_data)
def process_grocery_receipt(self, transaction, items_with_prices):
"""Process a grocery receipt with multiple items using OO-style method."""
# Calculate totals
subtotal = sum(item['price'] for item in items_with_prices)
tax_rate = 0.20 # 20% VAT
tax_amount = subtotal * tax_rate
total = subtotal + tax_amount
receipt_info = {
"merchant_name": "Grocery Store",
"total_amount": int(total * 100), # Convert to pence
"currency": "GBP",
"items": [
{
"description": item["name"],
"unit_price": int(item["price"] * 100),
"quantity": item.get("quantity", 1),
"total_price": int(item["price"] * item.get("quantity", 1) * 100)
}
for item in items_with_prices
],
"taxes": [
{
"description": "VAT",
"rate": tax_rate,
"amount": int(tax_amount * 100)
}
]
}
return self.create_detailed_receipt(transaction, receipt_info)
def find_transactions_without_receipts(self, days=7):
"""Find recent transactions that don't have receipts."""
accounts = self.client.accounts.list()
current_account = accounts[0] # Use first account
# Get recent transactions
from datetime import timedelta
since = datetime.now(tz=datetime.timezone.utc) - timedelta(days=days)
transactions = current_account.list_transactions(
since=since.isoformat(),
limit=50
)
# Filter for spending transactions without receipts
candidates = []
for txn in transactions:
if txn.amount < 0: # Spending transaction
# Check if it has attachments (simplified check)
if not txn.attachments:
candidates.append({
'id': txn.id,
'description': txn.description,
'amount': abs(txn.amount) / 100,
'created': txn.created,
'merchant': txn.merchant.name if txn.merchant else None
})
return candidates
# Usage examples
def main():
manager = ReceiptManager()
# Find transactions that need receipts
print("🔍 Finding transactions without receipts...")
transactions = manager.find_transactions_without_receipts(days=7)
print(f"Found {len(transactions)} transactions without receipts:")
for txn in transactions[:5]: # Show first 5
print(f" 💸 {txn['description']}: £{txn['amount']:.2f}")
# Example: Add a grocery receipt
if transactions:
example_txn = transactions[0]
print(f"\n📄 Adding receipt to: {example_txn['description']}")
# Example grocery items
grocery_items = [
{"name": "Apples", "price": 2.50, "quantity": 2},
{"name": "Milk", "price": 1.20, "quantity": 1},
{"name": "Bread", "price": 0.95, "quantity": 1},
]
receipt = manager.process_grocery_receipt(
example_txn['id'],
grocery_items
)
if receipt:
print("✅ Grocery receipt added successfully")
if __name__ == "__main__":
main()
Integration Examples
Budget Tracking System
Complete budget tracking with categories and alerts:Copy
from monzoh import MonzoClient
from datetime import datetime, timedelta
from collections import defaultdict
import json
class BudgetTracker:
def __init__(self, budget_file="budget.json"):
self.client = MonzoClient()
self.budget_file = budget_file
self.load_budget()
def load_budget(self):
"""Load budget configuration from file."""
try:
with open(self.budget_file, 'r') as f:
self.budget = json.load(f)
except FileNotFoundError:
# Default budget
self.budget = {
"monthly_limits": {
"groceries": 400,
"eating_out": 200,
"transport": 100,
"shopping": 150,
"entertainment": 100
},
"total_monthly_limit": 1000,
"alert_thresholds": {
"warning": 0.8, # 80% of budget
"critical": 0.95 # 95% of budget
}
}
self.save_budget()
def save_budget(self):
"""Save budget configuration to file."""
with open(self.budget_file, 'w') as f:
json.dump(self.budget, f, indent=2)
def get_monthly_spending(self):
"""Get spending for the current month by category."""
accounts = self.client.accounts.list()
current_account = accounts[0]
# Get transactions for current month
now = datetime.now(tz=datetime.timezone.utc)
start_of_month = now.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
transactions = current_account.list_transactions(
since=start_of_month.isoformat(),
limit=500
)
# Categorize spending
spending = defaultdict(float)
total_spending = 0
for txn in transactions:
if txn.amount < 0: # Spending transaction
amount = abs(txn.amount) / 100
category = txn.category or "other"
spending[category] += amount
total_spending += amount
return dict(spending), total_spending
def check_budget_status(self):
"""Check current budget status and generate alerts."""
spending, total_spending = self.get_monthly_spending()
print("💰 Monthly Budget Status")
print("="*50)
print(f"📅 Month: {datetime.now(tz=datetime.timezone.utc).strftime('%B %Y')}")
print(f"💸 Total Spent: £{total_spending:.2f}")
print(f"🎯 Total Budget: £{self.budget['total_monthly_limit']:.2f}")
# Overall budget status
overall_usage = total_spending / self.budget['total_monthly_limit']
overall_percentage = overall_usage * 100
if overall_usage >= self.budget['alert_thresholds']['critical']:
status = "🚨 CRITICAL"
elif overall_usage >= self.budget['alert_thresholds']['warning']:
status = "⚠️ WARNING"
else:
status = "✅ OK"
print(f"📊 Overall Usage: {overall_percentage:.1f}% {status}")
remaining = self.budget['total_monthly_limit'] - total_spending
print(f"💳 Remaining: £{remaining:.2f}")
# Category breakdown
print(f"\n📋 Category Breakdown:")
print("-" * 50)
alerts = []
for category, limit in self.budget['monthly_limits'].items():
spent = spending.get(category, 0)
usage = spent / limit if limit > 0 else 0
percentage = usage * 100
if usage >= self.budget['alert_thresholds']['critical']:
status = "🚨"
alerts.append(f"CRITICAL: {category} budget exceeded ({percentage:.1f}%)")
elif usage >= self.budget['alert_thresholds']['warning']:
status = "⚠️"
alerts.append(f"WARNING: {category} approaching limit ({percentage:.1f}%)")
else:
status = "✅"
remaining_cat = limit - spent
print(f" {category.title():<15} £{spent:>7.2f} / £{limit:>7.2f} ({percentage:>5.1f}%) {status}")
print(f" Remaining: £{remaining_cat:.2f}")
# Show alerts
if alerts:
print(f"\n🔔 Budget Alerts:")
for alert in alerts:
print(f" {alert}")
return {
'total_spent': total_spending,
'total_budget': self.budget['total_monthly_limit'],
'usage_percentage': overall_percentage,
'category_spending': spending,
'alerts': alerts
}
def suggest_savings(self):
"""Suggest ways to save money based on spending patterns."""
spending, total_spending = self.get_monthly_spending()
suggestions = []
# Find categories over budget
for category, limit in self.budget['monthly_limits'].items():
spent = spending.get(category, 0)
if spent > limit:
excess = spent - limit
suggestions.append(
f"Reduce {category} spending by £{excess:.2f} to stay within budget"
)
# General suggestions based on spending patterns
if spending.get('eating_out', 0) > 150:
suggestions.append("Consider cooking more meals at home to reduce eating out expenses")
if spending.get('shopping', 0) > spending.get('groceries', 0):
suggestions.append("Your shopping spending exceeds groceries - review non-essential purchases")
return suggestions
def set_category_limit(self, category, limit):
"""Set budget limit for a specific category."""
self.budget['monthly_limits'][category] = limit
self.save_budget()
print(f"✅ Set {category} budget to £{limit:.2f}")
def weekly_report(self):
"""Generate a weekly spending report."""
accounts = self.client.accounts.list()
current_account = accounts[0]
# Get last 7 days of transactions
since = datetime.now(tz=datetime.timezone.utc) - timedelta(days=7)
transactions = current_account.list_transactions(
since=since.isoformat(),
limit=100
)
spending_by_day = defaultdict(float)
category_spending = defaultdict(float)
for txn in transactions:
if txn.amount < 0:
amount = abs(txn.amount) / 100
day = datetime.fromisoformat(txn.created.replace('Z', '+00:00')).date()
category = txn.category or "other"
spending_by_day[day] += amount
category_spending[category] += amount
print("📅 Weekly Spending Report")
print("="*40)
total_week = sum(spending_by_day.values())
print(f"💸 Total spent this week: £{total_week:.2f}")
print(f"📊 Daily average: £{total_week/7:.2f}")
print(f"\nDaily breakdown:")
for day in sorted(spending_by_day.keys()):
amount = spending_by_day[day]
print(f" {day.strftime('%A %d/%m')}: £{amount:.2f}")
if category_spending:
print(f"\nTop categories this week:")
for category, amount in sorted(category_spending.items(), key=lambda x: x[1], reverse=True)[:3]:
print(f" {category.title()}: £{amount:.2f}")
def main():
tracker = BudgetTracker()
# Check current budget status
status = tracker.check_budget_status()
# Get savings suggestions
suggestions = tracker.suggest_savings()
if suggestions:
print(f"\n💡 Savings Suggestions:")
for suggestion in suggestions:
print(f" • {suggestion}")
# Weekly report
print(f"\n" + "="*60)
tracker.weekly_report()
if __name__ == "__main__":
main()