Reconciles QuickBooks Online payroll GL accounts against payroll provider reports (Gusto, ADP, Paychex) to catch missed journal entries, manual adjustments, and tax filing discrepancies before they become audit findings or payroll tax penalties.
Use when:
Do NOT use when:
bank-reconciliation-agentpl-deep-analysistext
scripts/pipelines/payroll-reconciliation.py
bash
# Monthly reconciliation
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--month 2026-03 \
--payroll-file ~/Downloads/gusto-march-2026.csv
# Quarterly 941 reconciliation
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--quarter 2026-Q1 \
--payroll-file ~/Downloads/gusto-q1-2026.csv \
--form-941-file ~/Downloads/941-q1.csv
# Annual W-2 helper
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--year 2026 \
--payroll-file ~/Downloads/gusto-annual-2026.csv \
--w2-mode
# Custom date range
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--start 2026-01-01 --end 2026-06-30 \
--payroll-file ~/Downloads/h1-2026.csv
# Provider analysis only (no QBO connection needed)
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--month 2026-03 \
--payroll-file ~/Downloads/adp-report.csv \
--skip-gl
# Custom output directory
python3 scripts/pipelines/payroll-reconciliation.py \
--slug CLIENT_SLUG \
--month 2026-03 \
--payroll-file ~/Downloads/report.csv \
--out ~/Desktop/reports
ArgumentRequiredDescription--slugYesClient QBO slug identifier--payroll-fileYesPath to payroll provider CSV--monthOne ofYYYY-MM for single month--quarterOne ofYYYY-Q1 through YYYY-Q4--yearOne ofFull year (YYYY) for annual/W-2--start / --endOne ofCustom range (YYYY-MM-DD)--form-941-fileNoForm 941 CSV for quarterly tax recon--w2-modeNoEnable full W-2 box verification output--skip-glNoSkip QBO GL pull — provider analysis only--sandboxNoUse QBO sandbox environment--thresholdNoDiscrepancy threshold (default: $1.00)--outNoOutput directory (default: current dir)
The script auto-detects the payroll provider from CSV headers:
ProviderDetection SignatureGustoHeaders contain Check Date + Gross EarningsADPHeaders contain Pay Date + Total GrossPaychexHeaders contain Check Date + Regular EarningsGenericFallback — best-effort column matching
For unsupported formats, rename CSV columns to match any of the above signatures, or use the Generic fallback with standard column names (Gross, FIT, SIT, etc.).
The pipeline reconciles 12 payroll categories between GL and provider:
#CategoryGL Keywords941 Line1Gross Wageswages, salaries, payroll-salariesLine 22Federal Income Tax (FIT)federal withholding, fit, federal taxLine 33State Income Tax (SIT)state withholding, sit, state tax—4SS Employer (FICA-SS ER)social security employer, ss erLine 5a5SS Employee (FICA-SS EE)social security employee, ss eeLine 5a6Medicare Employer (FICA-Med ER)medicare employer, med erLine 5c7Medicare Employee (FICA-Med EE)medicare employee, med eeLine 5c8FUTA / SUTAfuta, suta, unemployment tax—9Health Insurancehealth insurance, medical, dentalW-2 Box 12C10401k / Retirement401k, retirement, pensionW-2 Box 12D11Workers Compensationworkers comp, wc premium—12PTO Accrualpto, vacation accrual, leave accrual—
Discrepancy threshold: ±$1.00 per category (configurable via --threshold).
Three sections:
text
payroll-recon_{slug}_{period}.xlsx
Examples:
payroll-recon_sb-paulson_2026-03.xlsxpayroll-recon_willo-salons_2026-Q1.xlsxpayroll-recon_glowlabs_2026.xlsxbash
pip install openpyxl
Node.js QBO client (auth token required for GL pull).
Change data is persisted at:
text
.cache/payroll-reconciliation/{slug}.json
Keeps last 24 periods. Delete to reset baseline.
This pipeline integrates with the Month-End Close checklist
( scripts/pipelines/month-end-close.py). Run sequence:
payroll-reconciliation.py for the closed month--year + --w2-mode for Box verificationIf providing a 941 CSV ( --form-941-file), the pipeline expects columns:
text
line, amount
Example rows:
text
Line 2 - Total wages, 125000.00
Line 3 - Federal income tax withheld, 18750.00
Line 5a - Social security wages, 15500.00
Line 5c - Medicare wages, 3625.00
Line 6 - Total taxes, 37875.00
Column names are matched case-insensitively. Extra columns are ignored.
"QBO CLI error (exit 1)" → Refresh the QBO auth token for this client slug.
"Payroll file not found"
→ Verify the path in --payroll-file. Use absolute path if needed.
"Provider detected: Generic" → Column headers didn't match Gusto/ADP/Paychex signatures. Results are best-effort. → Rename columns or use the Generic field names listed in the parser section.
All categories show $0 for GL
→ GL pull succeeded but no accounts matched payroll keywords.
→ Check QBO account names — they may use custom names. Add keywords to PAYROLL_ACCOUNT_KEYWORDS.
Discrepancy threshold too sensitive
→ Use --threshold 5.00 to allow up to $5 variance (useful for rounding-heavy providers).
Decimal — no float arithmetic anywhere.