Skip to main content

A Python library for the Monzo Developer API

Project description

Package version Python versions License Ruff py.typed Coverage Status

Hero

A Python library for the Monzo Developer API.

📖 View Full Documentation

Features

  • 📦 Trusted PyPI publishing
  • 🌐 Full Monzo API coverage
  • 🔐 Simple OAuth2 authentication flow
  • 🔒 Type-safe with Pydantic models
  • ⚡ Async/await support with httpx
  • ✅ Well-tested and documented
  • ⚠️ Comprehensive error handling

Installation

uv add monzoh

Quick Start

  1. Create an OAuth2 client on the Monzo Developers Portal. Redirect URL must be http://localhost:8080/callback and Confidentiality must be Confidential.
  2. Run monzo-auth and complete the login flow.
  3. Authorise access on the Monzo app.

You can now use the API:

from monzoh import MonzoClient

client = MonzoClient() # Uses cached access token and handles refresh

account = client.accounts.list()[0]
balance = account.get_balance()
print(f"Balance: £{balance.balance}")

transactions = account.list_transactions(limit=10)
for transaction in transactions:
    if transaction.amount < -50:  # Transactions over £50
        transaction.annotate({"notes": "#large_expense"})

transactions[0].upload_attachment("image.jpg")

pots = account.list_pots()
for pot in pots:
    if pot.name == "Savings":
        pot.deposit(10.00)
        break

Asynchronous API

import asyncio
from monzoh import AsyncMonzoClient

async def main():
    async with AsyncMonzoClient() as client:
        account = (await client.accounts.list())[0]
        
        balance = await account.aget_balance()
        print(f"Balance: £{balance.balance}")
        
        transactions = await account.alist_transactions(limit=10)
        for transaction in transactions:
            if transaction.amount < -50:
                await transaction.aannotate({"notes": "#large_expense"})
        
        pots = await account.alist_pots()
        for pot in pots:
            if pot.name == "Savings":
                await pot.adeposit(10.00)
                break

asyncio.run(main())

Why not call the API directly?

It's much simpler with Monzoh! As an example, here's what uploading an attachment looks like, compared with using the API directly:

With monzoh

from monzoh import MonzoClient

client = MonzoClient()
account = client.accounts.list()[0]
transaction = account.list_transactions(limit=1)[0]
attachment = transaction.upload_attachment("receipt.jpg")

Without monzoh

import requests
from pathlib import Path

accounts_response = requests.get(
    "https://api.monzo.com/accounts",
    headers={"Authorization": f"Bearer {access_token}"}
)
account_id = accounts_response.json()["accounts"][0]["id"]

transactions_response = requests.get(
    "https://api.monzo.com/transactions",
    headers={"Authorization": f"Bearer {access_token}"},
    params={"account_id": account_id, "limit": 1}
)
transaction_id = transactions_response.json()["transactions"][0]["id"]

response = requests.post(
    "https://api.monzo.com/attachment/upload",
    headers={"Authorization": f"Bearer {access_token}"},
    data={
        "file_name": "receipt.jpg",
        "file_type": "image/jpeg",
        "content_length": str(len(Path("receipt.jpg").read_bytes()))
    }
)
upload_info = response.json()

file_data = Path("receipt.jpg").read_bytes()
requests.put(
    upload_info["upload_url"], 
    data=file_data,
    headers={
        "Content-Type": "image/jpeg",
        "Content-Length": str(len(file_data))
    }
)

requests.post(
    "https://api.monzo.com/attachment/register",
    headers={"Authorization": f"Bearer {access_token}"},
    data={
        "external_id": transaction_id,
        "file_url": upload_info["file_url"],
        "file_type": "image/jpeg"
    }
)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

monzoh-1.2.0.tar.gz (5.2 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

monzoh-1.2.0-py3-none-any.whl (51.8 kB view details)

Uploaded Python 3

File details

Details for the file monzoh-1.2.0.tar.gz.

File metadata

  • Download URL: monzoh-1.2.0.tar.gz
  • Upload date:
  • Size: 5.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for monzoh-1.2.0.tar.gz
Algorithm Hash digest
SHA256 0a38fc07428e15e395b7dbc92cb0ef4fb7de8bd57ae91bd93e4a9f179f033d7f
MD5 aa381b2dd063bbc3aee929526e5d571d
BLAKE2b-256 0a9bcfd0c78c6f6dec744ab7b90073a7fc545909bd91c4fd39d448f48e03f996

See more details on using hashes here.

Provenance

The following attestation bundles were made for monzoh-1.2.0.tar.gz:

Publisher: publish.yml on samdobson/monzoh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file monzoh-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: monzoh-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 51.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for monzoh-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 06675f040e86285e486b602d9a3ae342571c450676ba590c751b2923e3cfbbdb
MD5 530f54de87c67bb4e53fdedb69b6f782
BLAKE2b-256 5e2c7ddaf8aa87587ae43fb293f5926f8f1ab4501a64e2bda6b6eed5774fe342

See more details on using hashes here.

Provenance

The following attestation bundles were made for monzoh-1.2.0-py3-none-any.whl:

Publisher: publish.yml on samdobson/monzoh

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page