Command-line interface for QuickBooks Online API
Project description
qbo-cli
A command-line interface for the QuickBooks Online API. Query entities, run reports, create invoices — all from your terminal. The QuickBooks CLI that developers actually want to use.
Built for QuickBooks automation — giving AI agents (like OpenClaw) and scripts clean, direct QBO command line access without dealing with unmaintained MCP servers or raw API calls every time. Also works great as a standalone QuickBooks API Python tool for developers who live in the terminal.
Features
- OAuth 2.0 authentication with local callback server or manual mode
- Query entities using QBO's SQL-like syntax with automatic pagination
- CRUD operations on any QBO entity (Customer, Invoice, Bill, etc.)
- Financial reports — P&L, Balance Sheet, Cash Flow, and more
- Raw API access for anything the CLI doesn't cover
- Auto token refresh — access tokens refresh transparently
- TSV and JSON output — pipe to
jq,awk, spreadsheets - Sandbox support for development and testing
- File-locked token storage — safe for concurrent use
Installation
pip install qbo-cli
Requires Python 3.9+.
Setup
1. Create an Intuit Developer App
Go to developer.intuit.com, create an app, and note your Client ID and Client Secret.
Add a Redirect URI in your app's settings. For production apps, Intuit requires HTTPS with a real domain (e.g., https://yourapp.example.com/callback). For development, https://developer.intuit.com/v2/OAuth2Playground/RedirectUrl works. Set QBO_REDIRECT_URI to match.
Tip: If you're running on a headless server, use
qbo auth init --manual— the redirect doesn't need to resolve. You'll just copy the URL from your browser's address bar after authorization.
2. Configure Credentials
Quickest: Interactive setup
qbo auth setup
This prompts for your Client ID, Client Secret, and Redirect URI, then saves to ~/.qbo/config.json.
Option A: Environment variables (for CI/scripts)
export QBO_CLIENT_ID="your-client-id"
export QBO_CLIENT_SECRET="your-client-secret"
Option B: Config file (~/.qbo/config.json)
{
"client_id": "your-client-id",
"client_secret": "your-client-secret"
}
Environment variables take precedence over the config file.
3. Authorize
qbo auth init
This opens an OAuth flow — authorize in your browser, and tokens are saved to ~/.qbo/tokens.json (chmod 600).
On headless servers, use manual mode:
qbo auth init --manual
Usage
Check auth status
qbo auth status
Query entities
# All customers
qbo query "SELECT * FROM Customer"
# Recent invoices
qbo query "SELECT * FROM Invoice WHERE TxnDate > '2025-01-01'"
# Unpaid invoices
qbo query "SELECT * FROM Invoice WHERE Balance > '0'"
# Vendors with email
qbo query "SELECT DisplayName, PrimaryEmailAddr FROM Vendor"
# Count items
qbo query "SELECT COUNT(*) FROM Item"
# TSV output (great for spreadsheets)
qbo query "SELECT DisplayName, Balance FROM Customer WHERE Balance > '0'" -f tsv
Queries automatically paginate through all results (up to 100 pages × 1000 rows).
Get a single entity
qbo get Customer 5
qbo get Invoice 1042
Create an entity
echo '{
"DisplayName": "John Smith",
"PrimaryEmailAddr": {"Address": "john@example.com"}
}' | qbo create Customer
echo '{
"CustomerRef": {"value": "5"},
"Line": [{
"Amount": 150.00,
"DetailType": "SalesItemLineDetail",
"SalesItemLineDetail": {"ItemRef": {"value": "1"}}
}]
}' | qbo create Invoice
Update an entity
# Fetch, modify, and update
qbo get Customer 5 | jq '.Customer.CompanyName = "New Name"' | qbo update Customer
Delete an entity
qbo delete Invoice 1042
The CLI fetches the entity first (to get the required SyncToken), then deletes it.
Run reports
# Profit and Loss for a date range
qbo report ProfitAndLoss --start-date 2025-01-01 --end-date 2025-12-31
# Balance Sheet as of today
qbo report BalanceSheet
# Using date macros
qbo report ProfitAndLoss --date-macro "Last Month"
qbo report ProfitAndLoss --date-macro "This Year"
# With extra parameters
qbo report ProfitAndLoss --start-date 2025-01-01 --end-date 2025-12-31 accounting_method=Cash
Available reports: ProfitAndLoss, BalanceSheet, CashFlow, CustomerIncome, AgedReceivables, AgedPayables, GeneralLedger, TrialBalance, and more.
Raw API access
# GET request
qbo raw GET "query?query=SELECT * FROM CompanyInfo"
# POST with body
echo '{"TrackQtyOnHand": true}' | qbo raw POST "item"
General Ledger reports (gl-report)
Hierarchical GL reports for any account and customer, with auto-discovered sub-account trees.
# Explore your chart of accounts
qbo gl-report --list-accounts
# Drill into a specific account's sub-accounts
qbo gl-report -a 125 --list-accounts
# Generate a report (JSON by default)
qbo gl-report -c "John Smith" -a 125
# Human-readable text with currency prefix
qbo gl-report -c "John Smith" -a 125 --text --currency USD
# Custom date range
qbo gl-report -c "John Smith" -a "Revenue" --start 2025-01-01 --end 2025-12-31
# Dates default to: first transaction → today
qbo gl-report -c "John Smith" -a 125 --text
Output formats
# JSON (default)
qbo query "SELECT * FROM Customer"
# TSV (tab-separated, for spreadsheets/awk)
qbo query "SELECT * FROM Customer" -f tsv
# Pipe to jq
qbo query "SELECT * FROM Customer" | jq '.[].DisplayName'
Sandbox mode
# Use sandbox API endpoint
qbo --sandbox query "SELECT * FROM Customer"
# Or set via env/config
export QBO_SANDBOX=true
Configuration Reference
| Setting | Env Variable | Config Key | Default |
|---|---|---|---|
| Client ID | QBO_CLIENT_ID |
client_id |
— |
| Client Secret | QBO_CLIENT_SECRET |
client_secret |
— |
| Redirect URI | QBO_REDIRECT_URI |
redirect_uri |
— (must match your Intuit app) |
| Realm ID | QBO_REALM_ID |
realm_id |
From auth flow |
| Sandbox mode | QBO_SANDBOX |
sandbox |
false |
Config file location: ~/.qbo/config.json
Token storage: ~/.qbo/tokens.json (created automatically, chmod 600)
Token Management
- Access tokens expire every 60 minutes. The CLI refreshes them automatically before each request.
- Refresh tokens are valid for 100 days. Each refresh extends the 100-day window (rolling expiry).
- If you don't use the CLI for 100+ days, the refresh token expires and you need to re-authorize with
qbo auth init. - The CLI warns you when the refresh token has fewer than 14 days remaining.
- Token refresh uses file locking — safe to run concurrent
qbocommands.
Force a manual refresh:
qbo auth refresh
Contributing
Contributions welcome. Please open an issue first to discuss what you'd like to change.
git clone https://github.com/alexph-dev/qbo-cli.git
cd qbo-cli
pip install -e .
License
MIT — see LICENSE.
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 qbo_cli-0.5.0.tar.gz.
File metadata
- Download URL: qbo_cli-0.5.0.tar.gz
- Upload date:
- Size: 19.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0b6cbcf95caf6c010e3326fc579ae13f6da55c475f458eb62f8394fd3c9fd6b
|
|
| MD5 |
43278178f53e0922218d9ae8b8f19658
|
|
| BLAKE2b-256 |
5760b3bcaf7d72dc9022b6e56671b75fe4438f0126fc61a1f3f57efde3ed01ac
|
File details
Details for the file qbo_cli-0.5.0-py3-none-any.whl.
File metadata
- Download URL: qbo_cli-0.5.0-py3-none-any.whl
- Upload date:
- Size: 20.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
abf80695e1023b4aa498532bd1cf120207148fdab6a62a6f9bc2645967b94821
|
|
| MD5 |
8281f1fca553d58e366bad958edaef4b
|
|
| BLAKE2b-256 |
78d3521adf098539d657987e4957631b6dc41ea4393074e9c527109d0ca9fd37
|