QuickBooks Online Integration
QuickBooks Online Integration Skill

Use when integrating with QuickBooks Online for invoicing, estimates, customers, and payments. Handles OAuth 2.0 auth, token refresh, and sandbox/production environments.
---
name: quickbooks-online
description: "Use when integrating with QuickBooks Online for invoicing, estimates, customers, and payments. Handles OAuth 2.0 auth, token refresh, and sandbox/production environments."
version: "1.0.0"
author: Hermes Agent
license: MIT
metadata:
hermes:
tags: [quickbooks, intuit, accounting, invoicing, small-business]
related_skills: [crm-lite, estimator-engine, stripe-payments]
---
# QuickBooks Online Integration Skill
## Overview
Integrates a small business with QuickBooks Online for customer management, estimates, invoices, and payment tracking. Uses Intuit's OAuth 2.0 flow with automatic token refresh. Designed for agent-mediated use: owners text commands, agent executes QB API calls.
## When to UseOverview
Use when integrating with QuickBooks Online for invoicing, estimates, customers, and payments. Handles OAuth 2.0 auth, token refresh, and sandbox/production environments.
Manual install (npx, ZIP)
Claude Code
npx skills add hewi333/Mom-n-Pop-Skills --skill quickbooks-online -g -a claude-codeClaude Code (degit)
npx degit hewi333/Mom-n-Pop-Skills/skills/quickbooks-online#main ~/.claude/skills/quickbooks-onlineClaude.ai / desktop
Codex, Cursor, other agents
Connects with Agent Alley MCP · agentalley.io/mcp
Files included
SKILL.md7.5 KB
Read SKILL.md here
SKILL.md
Show the full text217 lines
QuickBooks Online Integration Skill
Overview
Integrates a small business with QuickBooks Online for customer management, estimates, invoices, and payment tracking. Uses Intuit's OAuth 2.0 flow with automatic token refresh. Designed for agent-mediated use: owners text commands, agent executes QB API calls.
When to Use
- Create/send estimates from estimator-engine output
- Convert estimates to invoices when job is booked
- Record payments (Stripe webhook → QB payment)
- Sync customers between CRM and QB
- Pull reports for weekly owner summary (AR aging, revenue, outstanding estimates)
Don't Use For
- Complex inventory/assembly tracking
- Multi-currency or multi-entity accounting
- Payroll or tax filing
Authentication (OAuth 2.0)
Required Credentials (Environment Variables)
QBO_CLIENT_ID=*** From Intuit Developer Dashboard
QBO_CLIENT_SECRET= # From Intuit Developer Dashboard
QBO_REDIRECT_URI= # e.g., https://your-domain.com/qbo/callback
QBO_ENVIRONMENT= # "sandbox" or "production"
QBO_COMPANY_ID= # Realm ID (set after first auth)
Token Storage
- Store access_token + refresh_token + realm_id in
~/.hermes/qbo_tokens.json - Auto-refresh: access_token expires in 1 hour; refresh_token expires in 101 days
- On 401: refresh token, retry once, then force re-auth if refresh fails
Auth Flow
- User visits:
https://appcenter.intuit.com/connect/oauth2?client_id={id}&redirect_uri={uri}&scope=com.intuit.quickbooks.accounting&response_type=code&state={random} - Callback receives
code+realmId - Exchange code for tokens:
POST https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer - Store tokens + realm_id
Core API Operations
Customers
# Create customer (from CRM lead)
POST /v3/company/{realmId}/customer
{
"DisplayName": "John Smith",
"PrimaryEmailAddr": {"Address": "john@email.com"},
"PrimaryPhone": {"FreeFormNumber": "555-555-0123"},
"BillAddr": {"Line1": "123 Main St", "City": "[CITY]", "CountrySubDivisionCode": "[STATE]", "PostalCode": "[ZIP]"},
"Notes": "Lead from referral"
}
# Query customer
GET /v3/company/{realmId}/query?query=SELECT * FROM Customer WHERE DisplayName='John Smith'
Estimates
# Create estimate (from estimator-engine output)
POST /v3/company/{realmId}/estimate
{
"CustomerRef": {"value": "123"},
"TxnDate": "2026-01-15",
"ExpirationDate": "2026-02-14",
"Line": [
{
"DetailType": "SalesItemLineDetail",
"Amount": 3125.00,
"Description": "Service - 2500 sqft, vaulted ceilings, moderate tobacco",
"SalesItemLineDetail": {"ItemRef": {"value": "1", "name": "Base Treatment"}, "Qty": 2500, "UnitPrice": 1.25}
},
{"DetailType": "SalesItemLineDetail", "Amount": 350.00, "Description": "Cigarette >5yrs extended treatment", "SalesItemLineDetail": {"ItemRef": {"value": "2"}, "Qty": 1, "UnitPrice": 350}},
{"DetailType": "SalesItemLineDetail", "Amount": 75.00, "Description": "Travel surcharge - Premium Region", "SalesItemLineDetail": {"ItemRef": {"value": "3"}, "Qty": 1, "UnitPrice": 75}}
],
"CustomerMemo": {"value": "Valid 30 days. 50% deposit to schedule."}
}
# Send estimate email
POST /v3/company/{realmId}/estimate/{estimateId}/send?sendTo={email}
Invoices
# Create invoice from accepted estimate
POST /v3/company/{realmId}/invoice
{
"CustomerRef": {"value": "123"},
"TxnDate": "2026-01-20",
"DueDate": "2026-02-03",
"Line": [...same line items...],
"Deposit": 1562.50, # 50% deposit collected via Stripe
"CustomerMemo": {"value": "Balance due upon completion"}
}
# Get invoice PDF
GET /v3/company/{realmId}/invoice/{invoiceId}/pdf
Payments
# Record payment (from Stripe webhook)
POST /v3/company/{realmId}/payment
{
"CustomerRef": {"value": "123"},
"TotalAmt": 1562.50,
"PaymentRefNum": "pi_3StripePaymentIntentId",
"PaymentMethodRef": {"value": "5"}, # Credit Card
"DepositToAccountRef": {"value": "35"}, # Undeposited Funds
"Line": [{"Amount": 1562.50, "LinkedTxn": [{"TxnId": "456", "TxnType": "Invoice"}]}]
}
Items (Products/Services)
# Ensure service items exist (run once on setup)
# Base Treatment (per sqft)
# Cigarette Extended Treatment (each)
# Travel Surcharge (each)
# HVAC Duct Treatment (each)
# High Rise Surcharge (each)
# Region Surcharge (each)
Agent Integration Patterns
"Create estimate for John Smith at 123 Main St..."
# 1. Look up or create customer in QB
# 2. Call estimator-engine with property details
# 3. Transform estimator output → QB estimate line items
# 4. Create estimate in QB
# 5. Email PDF to customer
# 6. Create CRM estimate record (status=sent)
# 7. Create follow-up task (3 days)
"Customer accepted estimate #EST-0001-0042"
# 1. Update CRM estimate status=accepted
# 2. Create invoice in QB (copy line items)
# 3. Generate Stripe Payment Link for 50% deposit
# 4. Text customer deposit link
# 5. Create job scheduled task for the owner
"Record payment from Stripe webhook"
# 1. Verify webhook signature
# 2. Find invoice by payment_intent metadata
# 3. Create QB Payment linked to invoice
# 4. Update CRM invoice status=paid
# 5. Notify owners via Telegram
Common Pitfalls
- Token expiry — Always wrap API calls in try/except 401 → refresh → retry
- Sandbox vs production — Different base URLs, different realm IDs, different client credentials
- Minor version — Always send
minorversion=75header for latest API - Idempotency — Use
RequestIdheader for estimate/invoice creation to avoid duplicates - Rate limits — 500 requests/minute; implement exponential backoff
- Custom fields — QB custom fields need definition before use; use
Notesfield for flexibility - Tax — Many services are non-taxable; ensure items are marked non-taxable per your local tax rules
Verification Checklist
- OAuth flow completes and stores tokens
- Token refresh works (wait 1hr or force expiry)
- Create customer → appears in QB UI
- Create estimate with line items → PDF renders correctly
- Send estimate email → customer receives it
- Convert estimate to invoice → amounts match
- Record payment → invoice shows paid
- Weekly report pulls: outstanding estimates, AR aging, revenue MTD
One-Shot Recipes
"Sync new CRM lead to QuickBooks"
customer = qbo.upsert_customer(
name="Jane Doe",
email="jane@email.com",
phone="555-555-0199",
address="456 Palm Ave, [CITY], [STATE] [ZIP]",
notes="Referral - Example Realty"
)
"Push estimator output to QB estimate"
estimate = qbo.create_estimate(
customer_id=customer.id,
line_items=estimator_output.line_items, # [{desc, qty, unit_price, total}]
txn_date="2026-01-15",
expiration_date="2026-02-14",
memo="Valid 30 days. 50% deposit to schedule."
)
qbo.send_estimate(estimate.id, customer.email)
"Weekly owner report data"
report = qbo.get_weekly_report(realm_id)
# Returns: {outstanding_estimates: [...], ar_aging: {...}, revenue_mtd: 45000, payments_this_week: [...]}
| 1 | |
| 2 | name quickbooks-online |
| 3 | description "Use when integrating with QuickBooks Online for invoicing, estimates, customers, and payments. Handles OAuth 2.0 auth, token refresh, and sandbox/production environments." |
| 4 | version "1.0.0" |
| 5 | author Hermes Agent |
| 6 | license MIT |
| 7 | metadata |
| 8 | hermes |
| 9 | tags [quickbooks, intuit, accounting, invoicing, small-business] |
| 10 | related_skills [crm-lite, estimator-engine, stripe-payments] |
| 11 | |
| 12 | |
| 13 | # QuickBooks Online Integration Skill |
| 14 | |
| 15 | ## Overview |
| 16 | Integrates a small business with QuickBooks Online for customer management, estimates, invoices, and payment tracking. Uses Intuit's OAuth 2.0 flow with automatic token refresh. Designed for agent-mediated use: owners text commands, agent executes QB API calls. |
| 17 | |
| 18 | ## When to Use |
| 19 | **Create/send estimates** from estimator-engine output |
| 20 | **Convert estimates to invoices** when job is booked |
| 21 | **Record payments** (Stripe webhook → QB payment) |
| 22 | **Sync customers** between CRM and QB |
| 23 | **Pull reports** for weekly owner summary (AR aging, revenue, outstanding estimates) |
| 24 | |
| 25 | ## Don't Use For |
| 26 | Complex inventory/assembly tracking |
| 27 | Multi-currency or multi-entity accounting |
| 28 | Payroll or tax filing |
| 29 | |
| 30 | ## Authentication (OAuth 2.0) |
| 31 | |
| 32 | ### Required Credentials (Environment Variables) |
| 33 | |
| 34 | QBO_CLIENT_ID=*** From Intuit Developer Dashboard |
| 35 | QBO_CLIENT_SECRET= # From Intuit Developer Dashboard |
| 36 | QBO_REDIRECT_URI= # e.g., https://your-domain.com/qbo/callback |
| 37 | QBO_ENVIRONMENT= # "sandbox" or "production" |
| 38 | QBO_COMPANY_ID= # Realm ID (set after first auth) |
| 39 | |
| 40 | |
| 41 | ### Token Storage |
| 42 | Store access_token + refresh_token + realm_id in `~/.hermes/qbo_tokens.json` |
| 43 | Auto-refresh: access_token expires in 1 hour; refresh_token expires in 101 days |
| 44 | On 401: refresh token, retry once, then force re-auth if refresh fails |
| 45 | |
| 46 | ### Auth Flow |
| 47 | User visits: `https://appcenter.intuit.com/connect/oauth2?client_id={id}&redirect_uri={uri}&scope=com.intuit.quickbooks.accounting&response_type=code&state={random}` |
| 48 | Callback receives `code` + `realmId` |
| 49 | Exchange code for tokens: `POST https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer` |
| 50 | Store tokens + realm_id |
| 51 | |
| 52 | ## Core API Operations |
| 53 | |
| 54 | ### Customers |
| 55 | |
| 56 | # Create customer (from CRM lead) |
| 57 | POST /v3/company/{realmId}/customer |
| 58 | { |
| 59 | "DisplayName": "John Smith", |
| 60 | "PrimaryEmailAddr": {"Address": "john@email.com"}, |
| 61 | "PrimaryPhone": {"FreeFormNumber": "555-555-0123"}, |
| 62 | "BillAddr": {"Line1": "123 Main St", "City": "[CITY]", "CountrySubDivisionCode": "[STATE]", "PostalCode": "[ZIP]"}, |
| 63 | "Notes": "Lead from referral" |
| 64 | } |
| 65 | |
| 66 | # Query customer |
| 67 | GET /v3/company/{realmId}/query?query=SELECT * FROM Customer WHERE DisplayName='John Smith' |
| 68 | |
| 69 | |
| 70 | ### Estimates |
| 71 | |
| 72 | # Create estimate (from estimator-engine output) |
| 73 | POST /v3/company/{realmId}/estimate |
| 74 | { |
| 75 | "CustomerRef": {"value": "123"}, |
| 76 | "TxnDate": "2026-01-15", |
| 77 | "ExpirationDate": "2026-02-14", |
| 78 | "Line": [ |
| 79 | { |
| 80 | "DetailType": "SalesItemLineDetail", |
| 81 | "Amount": 3125.00, |
| 82 | "Description": "Service - 2500 sqft, vaulted ceilings, moderate tobacco", |
| 83 | "SalesItemLineDetail": {"ItemRef": {"value": "1", "name": "Base Treatment"}, "Qty": 2500, "UnitPrice": 1.25} |
| 84 | }, |
| 85 | {"DetailType": "SalesItemLineDetail", "Amount": 350.00, "Description": "Cigarette >5yrs extended treatment", "SalesItemLineDetail": {"ItemRef": {"value": "2"}, "Qty": 1, "UnitPrice": 350}}, |
| 86 | {"DetailType": "SalesItemLineDetail", "Amount": 75.00, "Description": "Travel surcharge - Premium Region", "SalesItemLineDetail": {"ItemRef": {"value": "3"}, "Qty": 1, "UnitPrice": 75}} |
| 87 | ], |
| 88 | "CustomerMemo": {"value": "Valid 30 days. 50% deposit to schedule."} |
| 89 | } |
| 90 | |
| 91 | # Send estimate email |
| 92 | POST /v3/company/{realmId}/estimate/{estimateId}/send?sendTo={email} |
| 93 | |
| 94 | |
| 95 | ### Invoices |
| 96 | |
| 97 | # Create invoice from accepted estimate |
| 98 | POST /v3/company/{realmId}/invoice |
| 99 | { |
| 100 | "CustomerRef": {"value": "123"}, |
| 101 | "TxnDate": "2026-01-20", |
| 102 | "DueDate": "2026-02-03", |
| 103 | "Line": [...same line items...], |
| 104 | "Deposit": 1562.50, # 50% deposit collected via Stripe |
| 105 | "CustomerMemo": {"value": "Balance due upon completion"} |
| 106 | } |
| 107 | |
| 108 | # Get invoice PDF |
| 109 | GET /v3/company/{realmId}/invoice/{invoiceId}/pdf |
| 110 | |
| 111 | |
| 112 | ### Payments |
| 113 | |
| 114 | # Record payment (from Stripe webhook) |
| 115 | POST /v3/company/{realmId}/payment |
| 116 | { |
| 117 | "CustomerRef": {"value": "123"}, |
| 118 | "TotalAmt": 1562.50, |
| 119 | "PaymentRefNum": "pi_3StripePaymentIntentId", |
| 120 | "PaymentMethodRef": {"value": "5"}, # Credit Card |
| 121 | "DepositToAccountRef": {"value": "35"}, # Undeposited Funds |
| 122 | "Line": [{"Amount": 1562.50, "LinkedTxn": [{"TxnId": "456", "TxnType": "Invoice"}]}] |
| 123 | } |
| 124 | |
| 125 | |
| 126 | ### Items (Products/Services) |
| 127 | |
| 128 | # Ensure service items exist (run once on setup) |
| 129 | # Base Treatment (per sqft) |
| 130 | # Cigarette Extended Treatment (each) |
| 131 | # Travel Surcharge (each) |
| 132 | # HVAC Duct Treatment (each) |
| 133 | # High Rise Surcharge (each) |
| 134 | # Region Surcharge (each) |
| 135 | |
| 136 | |
| 137 | ## Agent Integration Patterns |
| 138 | |
| 139 | ### "Create estimate for John Smith at 123 Main St..." |
| 140 | |
| 141 | # 1. Look up or create customer in QB |
| 142 | # 2. Call estimator-engine with property details |
| 143 | # 3. Transform estimator output → QB estimate line items |
| 144 | # 4. Create estimate in QB |
| 145 | # 5. Email PDF to customer |
| 146 | # 6. Create CRM estimate record (status=sent) |
| 147 | # 7. Create follow-up task (3 days) |
| 148 | |
| 149 | |
| 150 | ### "Customer accepted estimate #EST-0001-0042" |
| 151 | |
| 152 | # 1. Update CRM estimate status=accepted |
| 153 | # 2. Create invoice in QB (copy line items) |
| 154 | # 3. Generate Stripe Payment Link for 50% deposit |
| 155 | # 4. Text customer deposit link |
| 156 | # 5. Create job scheduled task for the owner |
| 157 | |
| 158 | |
| 159 | ### "Record payment from Stripe webhook" |
| 160 | |
| 161 | # 1. Verify webhook signature |
| 162 | # 2. Find invoice by payment_intent metadata |
| 163 | # 3. Create QB Payment linked to invoice |
| 164 | # 4. Update CRM invoice status=paid |
| 165 | # 5. Notify owners via Telegram |
| 166 | |
| 167 | |
| 168 | ## Common Pitfalls |
| 169 | |
| 170 | **Token expiry** — Always wrap API calls in try/except 401 → refresh → retry |
| 171 | **Sandbox vs production** — Different base URLs, different realm IDs, different client credentials |
| 172 | **Minor version** — Always send `minorversion=75` header for latest API |
| 173 | **Idempotency** — Use `RequestId` header for estimate/invoice creation to avoid duplicates |
| 174 | **Rate limits** — 500 requests/minute; implement exponential backoff |
| 175 | **Custom fields** — QB custom fields need definition before use; use `Notes` field for flexibility |
| 176 | **Tax** — Many services are non-taxable; ensure items are marked non-taxable per your local tax rules |
| 177 | |
| 178 | ## Verification Checklist |
| 179 | [ ] OAuth flow completes and stores tokens |
| 180 | [ ] Token refresh works (wait 1hr or force expiry) |
| 181 | [ ] Create customer → appears in QB UI |
| 182 | [ ] Create estimate with line items → PDF renders correctly |
| 183 | [ ] Send estimate email → customer receives it |
| 184 | [ ] Convert estimate to invoice → amounts match |
| 185 | [ ] Record payment → invoice shows paid |
| 186 | [ ] Weekly report pulls: outstanding estimates, AR aging, revenue MTD |
| 187 | |
| 188 | ## One-Shot Recipes |
| 189 | |
| 190 | ### "Sync new CRM lead to QuickBooks" |
| 191 | |
| 192 | customer = qbo.upsert_customer( |
| 193 | name="Jane Doe", |
| 194 | email="jane@email.com", |
| 195 | phone="555-555-0199", |
| 196 | address="456 Palm Ave, [CITY], [STATE] [ZIP]", |
| 197 | notes="Referral - Example Realty" |
| 198 | ) |
| 199 | |
| 200 | |
| 201 | ### "Push estimator output to QB estimate" |
| 202 | |
| 203 | estimate = qbo.create_estimate( |
| 204 | customer_id=customer.id, |
| 205 | line_items=estimator_output.line_items, # [{desc, qty, unit_price, total}] |
| 206 | txn_date="2026-01-15", |
| 207 | expiration_date="2026-02-14", |
| 208 | memo="Valid 30 days. 50% deposit to schedule." |
| 209 | ) |
| 210 | qbo.send_estimate(estimate.id, customer.email) |
| 211 | |
| 212 | |
| 213 | ### "Weekly owner report data" |
| 214 | |
| 215 | report = qbo.get_weekly_report(realm_id) |
| 216 | # Returns: {outstanding_estimates: [...], ar_aging: {...}, revenue_mtd: 45000, payments_this_week: [...]} |
| 217 |
Details
- Version
- 1.0.0
- License
- MIT
- Stars on the repo
- ★ 122
- Checked
- Source
- hewi333/Mom-n-Pop-Skills ↗
- Creator
- hewi333 · 12 listings
Similar skills
See all →
SkillFinance Operations
AgentBookkeeper & Controller
AgentStripe PayPal Integrator
SkillStripe Payment Integration
SkillInvoice Organization System
AgentPayment Integration SpecialistMore from hewi333
SkillConstruction Project Manager
SkillLightweight SQLite CRM
SkillService Pricing Calculator
SkillBusiness Financial Analyzer
SkillLead-to-Payment Pipeline
SkillMailchimp Integration Agent