Python SDK for Flo workflows - datasets, integrations, and workflow utilities
Project description
Flo Integration Modules
Python integration modules for Flo workflows running in Modal containers. These modules provide easy access to QuickBooks, Plaid, Jobber, Buildium, Rent Manager, and Hostaway integrations from within your Python workflows, with credentials automatically injected by the backend.
Overview
The Clyr backend automatically injects data source credentials into every workflow execution through a global __data_sources__ dictionary. Workflow developers can use these modules without worrying about credential management.
Table of Contents
- Installation
- Quick Start
- Available Modules
- Data Types
- How Credentials Work
- Error Handling
- Local Development
- Deployment
- Architecture
Installation
For Local Development
cd python-modules
pip install -e .
In Modal Workflows
The module is pre-installed in the Modal base image. Simply import and use:
from flo.quickbooks import QuickBooksClient
Quick Start
from flo.quickbooks import QuickBooksClient
# Automatically uses injected credentials (no parameters needed!)
qb = QuickBooksClient()
# Get vendors
vendors = qb.get_vendors()
print(f"Found {len(vendors)} vendors")
# Create a vendor
new_vendor = qb.create_vendor(
name="New Supplier LLC",
email="billing@newsupplier.com",
phone="555-1234"
)
print(f"Created vendor: {new_vendor.name} ({new_vendor.foreign_id})")
# Access vendor data
for vendor in vendors:
print(f"- {vendor.name}: {vendor.email}")
# Convert to dict for JSON serialization
vendor_dict = vendor.to_dict()
Available Modules
QuickBooks (flo.quickbooks)
Access QuickBooks data via Rutter API:
QuickBooksClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_vendors(limit=500): Get all vendors from QuickBooks- Returns:
List[Vendor] - Automatically handles pagination
- Returns:
-
create_vendor(name, email=None, phone=None, status='active', currency='USD', contact_name=None): Create a new vendor- Returns:
Vendor - Handles both sync and async Rutter responses
- Returns:
-
get_customers(limit=500): Get all customers from QuickBooks- Returns:
List[Customer] - Automatically handles pagination
- Returns:
-
get_accounts(limit=500): Get all chart of accounts entries- Returns:
List[Account] - Automatically handles pagination
- Returns:
-
get_invoices(limit=500): Get all invoices from QuickBooks- Returns:
List[Invoice] - Automatically handles pagination
- Returns:
-
get_classes(limit=500): Get all classes from QuickBooks- Returns:
List[Dict[str, Any]]
- Returns:
-
get_items(limit=500): Get all items from QuickBooks- Returns:
List[Dict[str, Any]]
- Returns:
-
get_tax_rates(limit=500): Get all tax rates from QuickBooks- Returns:
List[Dict[str, Any]]
- Returns:
Plaid (flo.plaid)
Access bank account and transaction data via Plaid API:
PlaidClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_accounts(): Get all bank accounts- Returns:
List[Account]
- Returns:
-
get_transactions(start_date, end_date, account_ids=None): Get transactions for a date range- Returns:
List[Transaction] - Args:
start_date:datetimeordateobjectend_date:datetimeordateobjectaccount_ids: Optional list of account IDs to filter by
- Returns:
-
get_balance(account_ids=None): Get account balances- Returns:
Dict[str, Any]with balance information - Args:
account_ids- Optional list of account IDs
- Returns:
-
get_institution(institution_id): Get institution details- Returns:
Institution - Args:
institution_id- Plaid institution ID
- Returns:
-
get_item(): Get Plaid item information- Returns:
Dict[str, Any]with item details
- Returns:
Jobber (flo.jobber)
Access Jobber field service management data via GraphQL API:
JobberClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_users(): Get all users from Jobber- Returns:
List[JobberUser] - Automatically handles pagination
- Returns:
-
get_clients(extra_ids=None): Get all clients from Jobber- Returns:
List[JobberClient] - Args:
extra_ids- Optional list of additional client IDs to fetch - Automatically handles pagination
- Returns:
-
get_jobs(): Get all jobs from Jobber- Returns:
List[JobberJob] - Automatically handles pagination
- Returns:
-
get_expenses(): Get all expenses from Jobber- Returns:
List[JobberExpense] - Automatically handles pagination
- Returns:
-
get_expense(expense_id): Get a specific expense by ID- Returns:
Optional[JobberExpense] - Args:
expense_id- Jobber expense ID
- Returns:
Buildium (flo.buildium)
Access Buildium property management data:
BuildiumClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_users(): Get all users from Buildium- Returns:
List[BuildiumUser] - Automatically handles pagination
- Returns:
-
get_vendors(): Get all vendors from Buildium- Returns:
List[BuildiumVendor] - Automatically handles pagination
- Returns:
-
get_gl_accounts(): Get all GL accounts from Buildium- Returns:
List[BuildiumGlAccount] - Automatically handles pagination
- Returns:
-
get_bills(paid_status=None): Get bills from Buildium- Returns:
List[BuildiumBill] - Args:
paid_status- Optional filter (e.g., "Unpaid", "Paid") - Automatically handles pagination
- Returns:
-
get_rentals(): Get all rental properties from Buildium- Returns:
List[BuildiumRental]
- Returns:
-
get_rental_owners(): Get all rental owners from Buildium- Returns:
List[BuildiumRentalOwner]
- Returns:
-
get_rental_units(): Get all rental units from Buildium- Returns:
List[BuildiumRentalUnit]
- Returns:
-
get_associations(): Get all associations from Buildium- Returns:
List[BuildiumAssociation]
- Returns:
-
get_association_owners(): Get all association owners from Buildium- Returns:
List[BuildiumAssociationOwner]
- Returns:
-
get_association_units(): Get all association units from Buildium- Returns:
List[BuildiumAssociationUnit]
- Returns:
-
get_work_orders(): Get all work orders from Buildium- Returns:
List[BuildiumWorkOrder]
- Returns:
Rent Manager (flo.rent_manager)
Access Rent Manager property management data:
RentManagerClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_users(): Get all users from Rent Manager- Returns:
List[RentManagerUser] - Automatically handles pagination
- Returns:
-
get_owners(): Get all owners from Rent Manager- Returns:
List[RentManagerOwner] - Automatically handles pagination
- Returns:
-
get_properties(): Get all properties from Rent Manager- Returns:
List[RentManagerProperty] - Automatically handles pagination
- Returns:
-
get_units(): Get all units from Rent Manager- Returns:
List[RentManagerUnit] - Automatically handles pagination
- Returns:
-
get_jobs(): Get all jobs from Rent Manager- Returns:
List[RentManagerJob] - Automatically handles pagination
- Returns:
-
get_credit_cards(): Get all credit cards from Rent Manager- Returns:
List[RentManagerCreditCard] - Automatically handles pagination
- Returns:
-
get_issues(): Get all issues from Rent Manager- Returns:
List[RentManagerIssue] - Automatically handles pagination (PageSize=500)
- Returns:
-
get_gl_accounts(): Get all GL accounts from Rent Manager- Returns:
List[RentManagerGlAccount] - Automatically handles pagination
- Returns:
-
get_vendors(): Get all vendors from Rent Manager- Returns:
List[RentManagerVendor] - Automatically handles pagination (PageSize=100)
- Returns:
Hostaway (flo.hostaway)
Access Hostaway vacation rental management data:
HostawayClient()
Initialize the client. Credentials are automatically loaded from injected data sources.
Methods:
-
get_listings(): Get all listings from Hostaway- Returns:
List[HostawayListing] - Automatically handles pagination
- Returns:
-
get_owners(): Get all owners from Hostaway- Returns:
List[HostawayOwner] - Automatically handles pagination
- Returns:
-
get_users(): Get all users from Hostaway- Returns:
List[HostawayUser] - Automatically handles pagination
- Returns:
-
get_units(): Get all units from Hostaway- Returns:
List[HostawayUnit] - Automatically handles pagination
- Returns:
Data Types
All data types are available in their respective modules (e.g., flo.quickbooks.models, flo.plaid.models). Each model includes a .to_dict() method that returns camelCase dictionaries matching the backend's DTO format.
QuickBooks Models
Vendor- Vendor informationCustomer- Customer informationAccount- Chart of accounts entryInvoice- Invoice dataExpense- Expense data
Plaid Models
Account- Bank account informationTransaction- Transaction dataInstitution- Financial institution details
Jobber Models
JobberUser- User informationJobberClient- Client informationJobberJob- Job/work order dataJobberExpense- Expense data
Buildium Models
BuildiumUser,BuildiumVendor,BuildiumGlAccount,BuildiumBillBuildiumRental,BuildiumRentalOwner,BuildiumRentalUnitBuildiumAssociation,BuildiumAssociationOwner,BuildiumAssociationUnitBuildiumWorkOrder
Rent Manager Models
RentManagerUser,RentManagerOwner,RentManagerProperty,RentManagerUnitRentManagerJob,RentManagerCreditCard,RentManagerIssueRentManagerGlAccount,RentManagerVendor
Hostaway Models
HostawayListing- Property listing informationHostawayOwner- Owner informationHostawayUser- User informationHostawayUnit- Unit information
How Credentials Work
The Clyr backend automatically injects a __data_sources__ global variable into every workflow execution:
__data_sources__ = {
"rutter": {
"id": "ds_xxx",
"platform": "quickbooks",
"access_token": "rutter_token_xxx",
"team_id": "team_yyy"
},
"plaid": {
"id": "ds_zzz",
"platform": "plaid",
"access_token": "plaid_token_xxx",
"item_id": "item_xxx",
"team_id": "team_yyy"
},
"jobber": {
"id": "ds_aaa",
"platform": "jobber",
"access_token": "jobber_token_xxx",
"team_id": "team_yyy"
}
}
All clients automatically read from this dictionary, so you never need to handle credentials manually.
Error Handling
from flo.exceptions import (
QuickBooksError,
PlaidError,
JobberError,
BuildiumError,
RentManagerError,
HostawayError,
AuthenticationError,
APIError,
DataSourceNotFoundError
)
try:
qb = QuickBooksClient()
vendors = qb.get_vendors()
except DataSourceNotFoundError as e:
print(f"Data source not found: {e}")
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except QuickBooksError as e:
print(f"QuickBooks error: {e}")
except APIError as e:
print(f"API error: {e}")
Context Manager
Use with context manager for automatic cleanup:
with QuickBooksClient() as qb:
vendors = qb.get_vendors()
# Session automatically closed
Manual Initialization (Testing)
For testing purposes, you can manually provide credentials:
qb = QuickBooksClient(
access_token="your_token",
team_id="team_id",
data_source_id="ds_id"
)
Local Development
Setup
- Set up Jupyter kernel (automatically done when deploying Modal image):
# From backend package directory
cd packages/backend
bun run deploy:modal
Or manually:
python3 packages/backend/scripts/setup-jupyter-kernel.py
This creates a virtual environment and Jupyter kernel matching the Modal container environment exactly.
- Configure backend API URL (optional):
Create a .env.local file in python-modules/ if you need a custom backend URL:
API_BASE_URL=http://localhost:3000
If not set, defaults to http://localhost:3000.
Prerequisites:
- Backend server must be running
- Backend must have access to the database and configured with all required environment variables (PLAID_CLIENT_ID, PLAID_SECRET, RUTTER_CLIENT_ID, etc.)
- You need a valid
team_idto fetch data sources
Note: Environment variables (like PLAID_CLIENT_ID, PLAID_SECRET, etc.) are automatically fetched from the backend and injected into your local Python environment, matching the Modal container behavior exactly. No need to configure them locally!
Jupyter Notebook Development
- Start Jupyter from the
python-modulesdirectory:
cd python-modules
jupyter notebook
-
When creating a new notebook, select the "Python (Flo Workflows)" kernel
-
In your notebook:
# At the start of your notebook
from dev_utils.jupyter_helper import load_team_data_sources
# Load data sources for your team
load_team_data_sources("team_123...")
# Now use the clients normally - credentials are automatically injected
from flo.plaid import PlaidClient
plaid = PlaidClient()
accounts = plaid.get_accounts()
from flo.jobber import JobberClient
jobber = JobberClient()
clients = jobber.get_clients()
Note: The Jupyter kernel uses the same Python packages and versions as Modal containers, ensuring your local development matches production exactly.
CLI Script Development
For running standalone Python scripts:
python dev_utils/cli_loader.py --team-id team_123... --script my_workflow.py
Or interactively:
python dev_utils/cli_loader.py --team-id team_123...
Programmatic Usage
from dev_utils.data_source_loader import inject_data_sources
# Load and inject data sources
inject_data_sources("team_123...")
# Your workflow code here
from flo.plaid import PlaidClient
plaid = PlaidClient()
Example Workflows
See the examples/ directory for complete workflow examples:
quickbooks/quickbooks_vendor_workflow.py- List and create vendorsquickbooks/quickbooks_invoice_report.py- Generate invoice summary reportplaid/plaid_transactions_workflow.py- Fetch and analyze transactionsjobber/get_jobber_expenses.py- Get Jobber expensesbuildium/get_buildium_vendors.py- Get Buildium vendorsrent_manager/get_rent_manager_properties.py- Get Rent Manager propertieshostaway/get_hostaway_listings.py- Get Hostaway listings
Deployment
Adding to Modal Image
The flo_integrations package is automatically included in the Modal runtime image. To deploy or update:
# From backend package directory
cd packages/backend
bun run deploy:modal
Or manually:
# From monorepo root
modal deploy packages/backend/scripts/build-modal-image.py
python3 packages/backend/scripts/setup-jupyter-kernel.py
This will:
- Build the Modal image with all Python dependencies from
requirements.txt - Include the
flo_integrationspackage frompython-modules/ - Create/update a Jupyter kernel matching the Modal environment
- Output an image ID (e.g.,
im-xxx...)
Important:
- The Modal image uses packages from
python-modules/requirements.txt(single source of truth) - The Jupyter kernel uses
python-modules/requirements-dev.txt(includes production + dev tools) - Note: The system now uses per-workflow-version images. Each workflow version builds its own image with the required dependencies.
Architecture
This package mirrors the functionality of the TypeScript backend integration modules (packages/backend/src/modules/integrations/) to provide consistent data access patterns for Python workflows.
The .to_dict() methods on all data types return camelCase dictionaries that match the backend's DTO format, making it easy to pass data between Python workflows and the backend.
Package Structure
python-modules/
├── flo_integrations/ # Main package
│ ├── quickbooks/ # QuickBooks integration
│ ├── plaid/ # Plaid integration
│ ├── jobber/ # Jobber integration
│ ├── buildium/ # Buildium integration
│ ├── rent_manager/ # Rent Manager integration
│ ├── hostaway/ # Hostaway integration
│ └── exceptions.py # Custom exceptions
├── dev_utils/ # Development utilities
│ ├── data_source_loader.py # Load data sources from backend
│ ├── jupyter_helper.py # Jupyter notebook helpers
│ └── cli_loader.py # CLI script runner
├── examples/ # Example workflow scripts
├── requirements.txt # Production dependencies
├── requirements-dev.txt # Development dependencies
└── setup.py # Package setup configuration
License
MIT
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file flo_sdk-0.9.1.tar.gz.
File metadata
- Download URL: flo_sdk-0.9.1.tar.gz
- Upload date:
- Size: 51.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4723cd3c1d409c040095cdf429d943ae597cb0903efa3788c03dc499ef13cc41
|
|
| MD5 |
13000036b1e7bce8ebee817254c9a8e4
|
|
| BLAKE2b-256 |
fdc3e42f92475735ba7eb9fb49b8c716e64815fe5387ce807d433d06eccc0551
|
Provenance
The following attestation bundles were made for flo_sdk-0.9.1.tar.gz:
Publisher:
publish-pypi.yml on CartysIO/Flo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flo_sdk-0.9.1.tar.gz -
Subject digest:
4723cd3c1d409c040095cdf429d943ae597cb0903efa3788c03dc499ef13cc41 - Sigstore transparency entry: 766026277
- Sigstore integration time:
-
Permalink:
CartysIO/Flo@21e8aff299c5976d72cfa815887ab36d2609455c -
Branch / Tag:
refs/heads/main - Owner: https://github.com/CartysIO
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@21e8aff299c5976d72cfa815887ab36d2609455c -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file flo_sdk-0.9.1-py3-none-any.whl.
File metadata
- Download URL: flo_sdk-0.9.1-py3-none-any.whl
- Upload date:
- Size: 56.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3af36e2526892a1b4cdaa093418989c9988944819beda6beef4ef926eda758b
|
|
| MD5 |
87c1626691dde5ab246220f035ecc2e3
|
|
| BLAKE2b-256 |
eb6c26b6a622e1efaa87a2ff2efc441267c9c7def39b640d31ea0de7cb1f4b5e
|
Provenance
The following attestation bundles were made for flo_sdk-0.9.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on CartysIO/Flo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
flo_sdk-0.9.1-py3-none-any.whl -
Subject digest:
d3af36e2526892a1b4cdaa093418989c9988944819beda6beef4ef926eda758b - Sigstore transparency entry: 766026284
- Sigstore integration time:
-
Permalink:
CartysIO/Flo@21e8aff299c5976d72cfa815887ab36d2609455c -
Branch / Tag:
refs/heads/main - Owner: https://github.com/CartysIO
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@21e8aff299c5976d72cfa815887ab36d2609455c -
Trigger Event:
workflow_dispatch
-
Statement type: