
Implementation Guide: Classify and code incoming transactions against chart of accounts automatically
Step-by-step implementation guide for deploying AI to classify and code incoming transactions against chart of accounts automatically for Accounting & Bookkeeping clients.
Hardware Procurement
Business Workstation
$850 per unit (MSP cost) / $1,150 suggested resale
Primary bookkeeper workstation for accessing QBO/Xero and AI classification dashboards. Modern browser-based workflow requires reliable compute but no GPU. Quantity scales with number of bookkeeper seats at the client firm.
Dual Monitor
$200 per unit (MSP cost) / $275 suggested resale
Dual-screen setup for bookkeepers reviewing AI-classified transactions: one screen for the bank feed/classification queue, one screen for the chart of accounts or client source documents. Significantly improves review throughput.
Document Scanner
$350 per unit (MSP cost) / $475 suggested resale
High-speed duplex scanner for digitizing paper receipts, invoices, and statements. Scanned images are uploaded to Dext or Hubdoc for OCR extraction, which feeds the AI classification pipeline. Required only if the client still receives paper documents.
Firewall/Security Appliance
$350 per unit (MSP cost) / $500 suggested resale
Business-grade firewall providing UTM, IPS, web filtering, and VPN for the accounting office network. Required for FTC Safeguards Rule compliance — accounting firms are classified as financial institutions and must implement network security controls. Includes FortiGuard subscription for threat intelligence.
Uninterruptible Power Supply
$220 per unit (MSP cost) / $300 suggested resale
Battery backup for workstation and networking equipment. Prevents data loss during power interruptions when bookkeepers are mid-review of AI-classified transaction batches. 1500VA capacity supports a workstation, dual monitors, and router/firewall for 15–20 minutes.
Software Procurement
QuickBooks Online Plus
$107/month per client entity (retail); MSP wholesale via QSP program at ~15-30% discount
Core cloud accounting platform with built-in Intuit Assist AI for transaction categorization. Plus tier provides class and location tracking essential for multi-dimensional CoA coding. Includes bank feed connections via Plaid. One subscription per client business entity.
Xero Standard (Growing)
$46/month per client entity; partner discounts available through Xero Partner Program
Alternative core accounting platform with built-in ML-based suggested categorization. Includes Hubdoc for document capture at no additional cost on qualifying plans. Preferred for clients with international operations or multi-currency needs.
Booke AI
$129/month per business entity; firm pricing from ~$20/client/month for multi-client deployments. MSP resale at $175–$250/entity/month.
AI-powered bookkeeping overlay that connects to QBO/Xero via OAuth. Auto-categorizes bank feed transactions against the chart of accounts using GPT-4 and custom ML models. Learns from bookkeeper corrections to improve over time. Handles invoice matching, receipt matching, and anomaly flagging. This is the primary AI classification engine for the solution.
Dext Prepare
~$37.50/month for 250 documents (Business plan); volume partner pricing available. MSP resale at $50–$65/month.
AI-powered document capture and OCR extraction for receipts, invoices, and bills. Extracts vendor name, date, amount, tax, line items, and publishes coded transactions directly to QBO/Xero general ledger. Feeds structured data into Booke AI and native platform AI for enhanced classification accuracy.
Hubdoc
Free with qualifying Xero plans; standalone ~$12/month
Alternative to Dext for Xero-centric deployments. Auto-fetches bills and statements from vendor portals, performs OCR, and pushes to Xero with suggested account coding. Best used when Xero is the core platform.
Docyt
$299–$999/month based on transaction volume. MSP resale at $400–$1,300/month.
Enterprise-tier AI accounting automation platform for higher-volume clients. Automates expense management, receipt processing, revenue reconciliation, and month-end close. Best for multi-entity clients with 500+ transactions/month. Alternative to Booke AI for larger deployments.
Rewind Backups for QBO/Xero
$9/month per QBO or Xero connection. MSP resale at $15–$20/month.
Automated daily backup of all QBO/Xero data including chart of accounts, transactions, contacts, and attachments. Critical safety net before enabling AI auto-posting — allows instant rollback if AI miscategorizes a batch of transactions.
DNSFilter
$1.15–$2.70/user/month depending on tier
DNS-layer security filtering to protect bookkeeper workstations from phishing and malware. Required as part of FTC Safeguards Rule compliance for accounting firms. Blocks access to known malicious domains that could compromise financial data.
SentinelOne Singularity
$4–$7/endpoint/month (MSP partner pricing); resale at $8–$12/endpoint/month
Next-gen endpoint protection (EDR/XDR) for all workstations accessing financial data. Provides AI-based threat detection, ransomware rollback, and compliance audit trails. Required for IRS Publication 4557 compliance.
Prerequisites
- Active QuickBooks Online (Plus or higher) or Xero (Standard/Growing or higher) subscription for each client entity to be onboarded
- Bank feeds connected and actively importing transactions in QBO/Xero — verify at least 30 days of transaction history is available
- Clean, standardized chart of accounts with consistent naming conventions. Chart should have 30–80 accounts maximum; overly granular charts (200+ accounts) must be consolidated first
- Multi-factor authentication (MFA) enabled on all QBO/Xero accounts, admin email accounts, and Booke AI/Dext accounts — non-negotiable for FTC Safeguards Rule compliance
- Firm administrator or accountant-level access to all client QBO/Xero files (not basic user access)
- Modern web browser installed and updated: Google Chrome 120+, Microsoft Edge 120+, or Mozilla Firefox 120+
- Reliable broadband internet: minimum 25 Mbps download / 10 Mbps upload per office location
- Business-grade firewall with UTM enabled (FortiGate 40F or equivalent) installed and configured
- Endpoint protection (SentinelOne or equivalent EDR) deployed on all workstations that will access financial data
- Written Information Security Plan (WISP) drafted or in progress — required by FTC Safeguards Rule for all accounting firms
- Designated security officer identified within the client firm (per FTC Safeguards Rule requirements)
- List of all client business entities to be onboarded, with transaction volumes per month, primary bank accounts, and current accounting platform version
- Inventory of existing integrations: payroll provider (Gusto, ADP, Paychex), POS system (Square, Shopify), expense cards (Ramp, Amex), and any other tools pushing journal entries into the GL
- Contact information for the client's lead bookkeeper or accountant who will serve as the domain expert for CoA mapping and rule configuration
Installation Steps
Step 1: Conduct Pre-Deployment Assessment and CoA Audit
Before touching any software, conduct a thorough assessment of the client's current accounting environment. Review the chart of accounts in each QBO/Xero instance for consistency, redundancy, and GAAP compliance. Identify transaction volumes, common vendors, and classification pain points. Document all existing integrations (payroll, POS, expense cards) that push data into the GL — the AI layer must be configured to ignore or properly handle these pre-coded entries. This step requires collaboration with the client's lead bookkeeper.
# In QBO: Navigate to Settings > Chart of Accounts > Export to Excel (Run Report > Account List > Export)
# In Xero: Navigate to Accounting > Chart of Accounts > Export (CSV)
# Document in a spreadsheet: Account Number | Account Name | Account Type | Sub-type | Active Status | Last 90 Day Transaction Count
# Identify: Duplicate accounts, unused accounts (0 transactions in 12 months), inconsistently named accounts, accounts missing from standard GAAP templateThis is the most critical step. AI classification accuracy is directly proportional to CoA quality. Budget 3-5 hours per client entity for this assessment. If the CoA has more than 150 accounts or has significant inconsistencies, recommend a CoA cleanup project ($2,000–$5,000 one-time fee) before proceeding.
Step 2: Standardize and Optimize the Chart of Accounts
Working with the client's bookkeeper, clean up the chart of accounts based on the Step 1 audit. Merge duplicate accounts, inactivate unused accounts, standardize naming conventions (e.g., always use 'Vendor Category - Subcategory' format), and ensure all accounts have correct types and detail types. This directly impacts AI classification accuracy because the ML model maps transactions to account names — ambiguous or duplicate names cause misclassification.
Never delete accounts that have historical transactions — always merge or archive. Maintain a change log documenting every CoA modification with date, old value, new value, and reason. This log is essential for audit trail compliance. Typical small business should have 30-50 active accounts; complex businesses may need 50-80.
Step 3: Enable and Verify Bank Feed Connections
Ensure all bank and credit card accounts are connected via direct bank feeds in QBO or Xero. Verify that transactions are importing correctly and that there are no stale or broken connections. Bank feeds are the primary data source for AI classification — if feeds are broken, the entire automation pipeline stops.
# In QBO: Navigate to Banking > Link Account > Select bank > Authenticate with bank credentials
# In QBO: Verify feed status — green checkmark = active; yellow/red = needs reconnection
# In Xero: Navigate to Accounting > Bank Accounts > Add Bank Account > Select institution > Authenticate
# Test: Wait 24 hours after connecting, then verify transactions are importing with correct dates and amounts
# For banks not supporting direct feeds: Set up CSV import workflow or Dext bank statement upload as fallbackCommon issue: bank feeds disconnect after password changes or bank security updates. Set up monitoring to check feed status weekly. Some credit unions and smaller banks have unreliable feeds via Plaid/Yodlee — for these, Dext can import statements via PDF upload as a workaround. Document all connected accounts with institution name, account last-4, and feed connection date.
Step 4: Deploy Rewind Backup for QBO/Xero
Before enabling any AI auto-classification, set up Rewind Backups on every QBO/Xero instance. This provides a safety net for rollback if the AI miscategorizes transactions in bulk. Rewind takes daily snapshots of all accounting data including transactions, chart of accounts, contacts, and attachments.
Rewind is $9/month per connection — non-negotiable for this project. The cost of one bulk misclassification rollback without backup (manual re-entry of hundreds of transactions) far exceeds years of Rewind subscription costs. Always deploy Rewind BEFORE enabling AI auto-posting in Step 8.
Step 5: Deploy Document Capture Platform (Dext or Hubdoc)
Set up Dext Prepare (for QBO clients) or Hubdoc (for Xero clients) to handle receipt, invoice, and bill capture. Configure the OCR extraction pipeline to automatically extract vendor name, date, amount, tax, and category from uploaded documents, then push coded transactions into the accounting platform. Train the client's team on submission methods (email forwarding, mobile app, desktop upload).
Dext's AI Assist feature can automatically suggest account coding — this works in tandem with Booke AI for multi-layer classification confidence. For the first 2 weeks, set Dext to 'Review before publish' mode so the bookkeeper validates OCR accuracy before documents flow into the GL. Common OCR errors: misreading handwritten totals, confusing tax amounts, duplicate submissions.
Step 6: Deploy Booke AI Classification Engine
Set up Booke AI as the primary AI transaction classification overlay. Booke AI connects to QBO/Xero via OAuth and applies GPT-4-based classification to categorize bank feed transactions against the chart of accounts. It also performs invoice matching, receipt matching, and anomaly detection. Configure it for each client entity the firm manages.
Start in 'Suggest Only' mode for the first 2-4 weeks. This allows the bookkeeper to review every AI suggestion, accept or correct it, and train the model. Switching to auto-post before the model has learned the client's specific patterns will create cleanup work. Booke AI's per-entity pricing at $129/month is the cost; for firms with 5+ clients, negotiate the per-client rate (~$20/client/month).
Step 7: Configure Classification Rules and Vendor Mappings
Set up deterministic classification rules for known, recurring transactions that should always map to the same account. These rules take precedence over AI inference and provide a reliable baseline. Common examples: rent payments always go to 6100-Rent Expense, payroll entries from Gusto always go to 6500-Payroll Expense, Stripe deposits always go to 4000-Revenue. Also configure vendor-specific mappings for the client's top 20-30 vendors.
Deterministic rules are the backbone of reliable classification. AI handles the long tail of infrequent or ambiguous transactions. Rule hierarchy: 1) Deterministic rules (exact matches), 2) AI classification (ML inference), 3) Manual review queue (low-confidence items). Budget 2-3 hours per client entity for initial rule configuration with the bookkeeper. Document all rules in a shared spreadsheet for audit purposes.
Step 8: Run AI Training Period in Suggest-Only Mode
With Booke AI in Suggest-Only mode, the bookkeeper processes 2-4 weeks of transactions by reviewing each AI suggestion and either accepting (confirming correct classification) or correcting (selecting the right account). Every correction trains the ML model. Monitor classification accuracy weekly and track improvement. Target: 85%+ accuracy by end of week 2, 90%+ by end of week 4.
The training period is non-negotiable. Skipping it results in poor accuracy and client frustration. The bookkeeper's time investment during this phase (typically 30-60 minutes/day for a client with 200-500 monthly transactions) pays dividends in long-term automation. If accuracy is below 80% after 2 weeks, revisit the chart of accounts — the problem is usually ambiguous account names, not the AI.
Step 9: Enable Auto-Classification and Configure Exception Handling
Once accuracy exceeds 90% consistently for 2+ weeks, switch Booke AI from Suggest-Only to Auto-Classify mode for transactions above the confidence threshold. Configure exception handling for low-confidence transactions, large amounts, new vendors, and specific account types that require human approval.
Start conservative with exception thresholds and relax over time as confidence builds. The $5,000 amount threshold should be adjusted based on client size — a company with $10M revenue might set this at $25,000. Never auto-post to equity accounts or inter-company accounts regardless of AI confidence. Review and adjust thresholds quarterly based on exception rate and error rate.
Step 10: Configure Security and Compliance Controls
Implement the security stack required by FTC Safeguards Rule and IRS Publication 4557. This includes endpoint protection, DNS filtering, access controls, audit logging, and encryption. Configure role-based access in QBO/Xero and Booke AI to enforce separation of duties.
FTC Safeguards Rule compliance is legally required for ALL accounting firms as of June 2023. Non-compliance can result in FTC enforcement action. The MSP should offer WISP creation as an add-on service ($1,500-$3,000 one-time + $200-$500/month ongoing compliance management). Maintain a compliance checklist and review quarterly. All security configurations should be documented in the WISP.
Step 11: Set Up Monitoring, Reporting, and Alerting
Configure monitoring dashboards and automated alerts to track AI classification performance, exception rates, and system health. Set up weekly and monthly reporting for the firm's management and for MSP internal tracking. This ensures ongoing quality and provides early warning of classification drift.
Classification accuracy should remain above 90% on an ongoing basis. If it drops below 85% for two consecutive weeks, trigger a review — common causes include: new vendor types the model hasn't seen, chart of accounts changes not reflected in rules, or seasonal transaction patterns (e.g., year-end adjustments). The MSP should include these monitoring activities in their managed service agreement.
Custom AI Components
Chart of Accounts Mapping Validator
Type: workflow
An automated validation workflow that runs before AI classification is enabled for a new client entity. It compares the client's chart of accounts against a standard GAAP template, identifies potential issues (duplicate accounts, missing standard accounts, ambiguous names), and generates a cleanup report. This ensures the CoA is AI-ready before the classification engine is activated.
Implementation:
# CoA Mapping Validator Workflow
# Platform: Python script run locally or as a cloud function
# Input: Exported CSV of client's chart of accounts from QBO/Xero
# Output: Validation report with issues and recommendations
import csv
import json
from collections import Counter
from difflib import SequenceMatcher
# Standard GAAP account types that should exist
STANDARD_ACCOUNTS = {
'Assets': ['Cash and Cash Equivalents', 'Accounts Receivable', 'Inventory', 'Prepaid Expenses', 'Fixed Assets', 'Accumulated Depreciation'],
'Liabilities': ['Accounts Payable', 'Credit Card Payable', 'Accrued Liabilities', 'Payroll Liabilities', 'Notes Payable', 'Line of Credit'],
'Equity': ['Owner Equity', 'Retained Earnings', 'Owner Draws'],
'Revenue': ['Service Revenue', 'Product Revenue', 'Other Income', 'Interest Income'],
'Expenses': ['Advertising', 'Auto Expense', 'Bank Charges', 'Contractor Expense', 'Depreciation', 'Dues and Subscriptions', 'Insurance', 'Interest Expense', 'Legal and Professional', 'Meals and Entertainment', 'Office Supplies', 'Payroll Expense', 'Rent Expense', 'Repairs and Maintenance', 'Software and Technology', 'Taxes and Licenses', 'Travel', 'Utilities']
}
def load_coa(filepath):
"""Load chart of accounts from CSV export."""
accounts = []
with open(filepath, 'r') as f:
reader = csv.DictReader(f)
for row in reader:
accounts.append({
'number': row.get('Account #', row.get('Code', '')).strip(),
'name': row.get('Account', row.get('Name', '')).strip(),
'type': row.get('Type', row.get('Account Type', '')).strip(),
'detail_type': row.get('Detail Type', '').strip(),
'active': row.get('Active', row.get('Status', 'Active')).strip()
})
return accounts
def check_duplicates(accounts):
"""Find accounts with similar names that may be duplicates."""
issues = []
names = [a['name'].lower() for a in accounts if a['active'].lower() in ('active', 'yes', 'true')]
for i, name1 in enumerate(names):
for j, name2 in enumerate(names[i+1:], i+1):
similarity = SequenceMatcher(None, name1, name2).ratio()
if similarity > 0.80 and name1 != name2:
issues.append({
'type': 'POTENTIAL_DUPLICATE',
'severity': 'HIGH',
'accounts': [accounts[i]['name'], accounts[j]['name']],
'similarity': f'{similarity:.0%}',
'recommendation': f'Review and merge: "{accounts[i]["name"]}" and "{accounts[j]["name"]}"'
})
return issues
def check_missing_standard(accounts):
"""Check for standard GAAP accounts that are missing."""
issues = []
active_names = [a['name'].lower() for a in accounts if a['active'].lower() in ('active', 'yes', 'true')]
for category, standard_list in STANDARD_ACCOUNTS.items():
for std_account in standard_list:
found = any(SequenceMatcher(None, std_account.lower(), name).ratio() > 0.70 for name in active_names)
if not found:
issues.append({
'type': 'MISSING_STANDARD_ACCOUNT',
'severity': 'MEDIUM',
'category': category,
'account': std_account,
'recommendation': f'Consider adding standard {category} account: "{std_account}"'
})
return issues
def check_naming_consistency(accounts):
"""Check for inconsistent naming patterns."""
issues = []
active = [a for a in accounts if a['active'].lower() in ('active', 'yes', 'true')]
# Check for accounts without numbers
no_numbers = [a for a in active if not a['number']]
if len(no_numbers) > 0 and len(no_numbers) < len(active):
issues.append({
'type': 'INCONSISTENT_NUMBERING',
'severity': 'MEDIUM',
'count': len(no_numbers),
'accounts': [a['name'] for a in no_numbers[:5]],
'recommendation': 'Some accounts have numbers and some do not. Standardize by assigning numbers to all accounts.'
})
# Check for very short or ambiguous names
for a in active:
if len(a['name']) < 4:
issues.append({
'type': 'AMBIGUOUS_NAME',
'severity': 'HIGH',
'account': a['name'],
'recommendation': f'Account name "{a["name"]}" is too short/ambiguous for AI classification. Rename to be descriptive.'
})
return issues
def check_account_count(accounts):
"""Check if total account count is in the optimal range for AI."""
issues = []
active = [a for a in accounts if a['active'].lower() in ('active', 'yes', 'true')]
count = len(active)
if count > 150:
issues.append({
'type': 'EXCESSIVE_ACCOUNTS',
'severity': 'HIGH',
'count': count,
'recommendation': f'{count} active accounts detected. Optimal range for AI classification is 30-80. Consolidate sub-accounts and use class/location tracking for dimensional analysis instead.'
})
elif count > 80:
issues.append({
'type': 'HIGH_ACCOUNT_COUNT',
'severity': 'MEDIUM',
'count': count,
'recommendation': f'{count} active accounts detected. Consider consolidating to 30-80 for optimal AI accuracy.'
})
elif count < 15:
issues.append({
'type': 'LOW_ACCOUNT_COUNT',
'severity': 'LOW',
'count': count,
'recommendation': f'Only {count} active accounts. This may lack granularity for meaningful financial reporting.'
})
return issues
def generate_report(filepath):
accounts = load_coa(filepath)
all_issues = []
all_issues.extend(check_duplicates(accounts))
all_issues.extend(check_missing_standard(accounts))
all_issues.extend(check_naming_consistency(accounts))
all_issues.extend(check_account_count(accounts))
report = {
'total_accounts': len(accounts),
'active_accounts': len([a for a in accounts if a['active'].lower() in ('active', 'yes', 'true')]),
'issues_found': len(all_issues),
'high_severity': len([i for i in all_issues if i['severity'] == 'HIGH']),
'medium_severity': len([i for i in all_issues if i['severity'] == 'MEDIUM']),
'low_severity': len([i for i in all_issues if i['severity'] == 'LOW']),
'ai_readiness': 'READY' if len([i for i in all_issues if i['severity'] == 'HIGH']) == 0 else 'NEEDS_CLEANUP',
'issues': all_issues
}
return json.dumps(report, indent=2)
if __name__ == '__main__':
import sys
if len(sys.argv) != 2:
print('Usage: python coa_validator.py <path_to_coa_export.csv>')
sys.exit(1)
print(generate_report(sys.argv[1]))Transaction Classification Rule Engine
Type: integration
A deterministic rule engine that applies client-specific business rules BEFORE the AI classification layer processes transactions. This ensures that known, recurring transactions (rent, payroll, subscriptions) are always coded correctly regardless of AI model behavior. Rules are defined in a YAML configuration file per client entity and processed in priority order.
Implementation:
# Transaction Classification Rule Engine
# Sits between bank feed ingestion and AI classification
# Rules in this engine take precedence over Booke AI suggestions
# --- rules_config.yaml (per client entity) ---
# File: /configs/clients/{client_id}/classification_rules.yaml
client_id: "acme-corp-001"
client_name: "ACME Corporation"
last_updated: "2025-01-15"
updated_by: "msp-tech@mspfirm.com"
global_settings:
confidence_threshold: 0.90
auto_post_enabled: true
max_auto_post_amount: 5000.00
require_approval_accounts:
- "3000" # Equity accounts
- "2100" # Notes Payable
- "9000" # Inter-company
new_vendor_action: "flag_for_review"
rules:
# Priority 1: Exact match rules (highest precedence)
- rule_id: "R001"
name: "Monthly Rent Payment"
priority: 1
conditions:
vendor_contains: ["ABC Property Management", "ABC Prop Mgmt"]
amount_range: {min: 4800, max: 5200}
transaction_type: "debit"
action:
account: "6100 - Rent Expense"
class: "General & Administrative"
memo: "Monthly office rent"
auto_post: true
- rule_id: "R002"
name: "Gusto Payroll"
priority: 1
conditions:
vendor_contains: ["Gusto", "ZP Gusto"]
transaction_type: "debit"
action:
account: "6500 - Payroll Expense"
memo: "Payroll processing - Gusto"
auto_post: true
skip_ai: true # Never send to AI; Gusto journal entries handle the detail
- rule_id: "R003"
name: "Stripe Revenue Deposits"
priority: 1
conditions:
vendor_contains: ["Stripe", "STRIPE TRANSFER"]
transaction_type: "credit"
action:
account: "4000 - Service Revenue"
memo: "Stripe payout"
auto_post: true
# Priority 2: Pattern match rules
- rule_id: "R010"
name: "Software Subscriptions"
priority: 2
conditions:
vendor_contains: ["Adobe", "Microsoft", "Google Workspace", "Zoom", "Slack", "Dropbox", "Notion", "Asana", "GitHub"]
amount_range: {min: 0, max: 1000}
transaction_type: "debit"
action:
account: "6210 - Software & Technology"
auto_post: true
- rule_id: "R011"
name: "AWS/Cloud Infrastructure"
priority: 2
conditions:
vendor_contains: ["Amazon Web Services", "AWS", "Google Cloud", "Microsoft Azure", "DigitalOcean", "Heroku"]
transaction_type: "debit"
action:
account: "6215 - Cloud Infrastructure"
auto_post: true
- rule_id: "R012"
name: "Business Insurance"
priority: 2
conditions:
vendor_contains: ["Hartford", "State Farm", "GEICO Commercial", "Hiscox", "Next Insurance", "Progressive Commercial"]
transaction_type: "debit"
action:
account: "6300 - Insurance Expense"
auto_post: false # Flag for review — may need allocation to specific insurance sub-accounts
# Priority 3: Category-based fallback rules
- rule_id: "R020"
name: "Restaurant/Meal Transactions"
priority: 3
conditions:
mcc_codes: [5812, 5813, 5814] # Restaurants, Bars, Fast Food
amount_range: {min: 0, max: 500}
transaction_type: "debit"
action:
account: "6400 - Meals & Entertainment"
auto_post: false # Always review — may need to split business vs. personal
- rule_id: "R021"
name: "Gas Stations"
priority: 3
conditions:
mcc_codes: [5541, 5542]
transaction_type: "debit"
action:
account: "6150 - Auto & Fuel Expense"
auto_post: true
# --- Python Rule Engine Implementation ---
import yaml
import re
from dataclasses import dataclass
from typing import Optional, List, Dict
@dataclass
class Transaction:
id: str
date: str
vendor_name: str
amount: float
transaction_type: str # 'credit' or 'debit'
mcc_code: Optional[int] = None
description: str = ''
@dataclass
class ClassificationResult:
transaction_id: str
account: str
class_name: Optional[str] = None
memo: Optional[str] = None
auto_post: bool = False
skip_ai: bool = False
rule_id: Optional[str] = None
confidence: float = 1.0 # Deterministic rules always 1.0
source: str = 'rule_engine'
def load_rules(config_path: str) -> dict:
with open(config_path, 'r') as f:
return yaml.safe_load(f)
def match_vendor(vendor_name: str, patterns: List[str]) -> bool:
vendor_lower = vendor_name.lower()
return any(p.lower() in vendor_lower for p in patterns)
def match_amount(amount: float, amount_range: dict) -> bool:
if not amount_range:
return True
return amount_range.get('min', 0) <= abs(amount) <= amount_range.get('max', float('inf'))
def match_mcc(mcc_code: Optional[int], mcc_codes: List[int]) -> bool:
if not mcc_codes or mcc_code is None:
return not mcc_codes # True if no MCC filter, False if filter exists but no MCC on transaction
return mcc_code in mcc_codes
def classify_transaction(txn: Transaction, config: dict) -> Optional[ClassificationResult]:
rules = sorted(config.get('rules', []), key=lambda r: r.get('priority', 99))
global_settings = config.get('global_settings', {})
for rule in rules:
conditions = rule.get('conditions', {})
matched = True
if 'vendor_contains' in conditions:
if not match_vendor(txn.vendor_name, conditions['vendor_contains']):
matched = False
if 'amount_range' in conditions and matched:
if not match_amount(txn.amount, conditions['amount_range']):
matched = False
if 'transaction_type' in conditions and matched:
if txn.transaction_type != conditions['transaction_type']:
matched = False
if 'mcc_codes' in conditions and matched:
if not match_mcc(txn.mcc_code, conditions['mcc_codes']):
matched = False
if matched:
action = rule.get('action', {})
auto_post = action.get('auto_post', False)
# Global override: check max auto-post amount
if auto_post and abs(txn.amount) > global_settings.get('max_auto_post_amount', 5000):
auto_post = False
# Global override: check if account requires approval
acct_number = action['account'].split(' ')[0] if action.get('account') else ''
if acct_number in global_settings.get('require_approval_accounts', []):
auto_post = False
return ClassificationResult(
transaction_id=txn.id,
account=action.get('account', 'UNCLASSIFIED'),
class_name=action.get('class'),
memo=action.get('memo'),
auto_post=auto_post,
skip_ai=action.get('skip_ai', False),
rule_id=rule['rule_id'],
confidence=1.0,
source='rule_engine'
)
return None # No rule matched — send to AI classification layer
# Usage:
# config = load_rules('/configs/clients/acme-corp-001/classification_rules.yaml')
# txn = Transaction(id='TXN-001', date='2025-01-15', vendor_name='GUSTO 01/15 PAYROLL', amount=-15234.56, transaction_type='debit')
# result = classify_transaction(txn, config)
# if result is None: send_to_booke_ai(txn) # Fallback to AI
# elif result.auto_post: post_to_qbo(result)
# else: add_to_review_queue(result)Classification Accuracy Monitor
Type: agent
A monitoring agent that runs weekly to analyze AI classification performance, detect accuracy drift, identify problematic vendors or account categories, and generate reports for the MSP and client firm. Alerts the MSP if accuracy drops below configurable thresholds. Designed to integrate with Booke AI's reporting API and QBO/Xero audit logs.
Implementation:
# Classification Accuracy Monitor Agent
# Runs weekly via cron/scheduled task
# Queries Booke AI API + QBO/Xero for classification metrics
# Generates alerts and reports
import json
import datetime
from dataclasses import dataclass, asdict
from typing import List, Dict, Optional
from collections import defaultdict
# --- Configuration ---
MONITOR_CONFIG = {
'accuracy_threshold_warning': 0.85,
'accuracy_threshold_critical': 0.80,
'exception_rate_threshold': 0.15, # 15% exception rate triggers alert
'min_transactions_for_analysis': 50,
'report_recipients': ['msp-team@mspfirm.com', 'admin@clientfirm.com'],
'alert_recipients': ['msp-alerts@mspfirm.com'],
'smtp_server': 'smtp.office365.com',
'smtp_port': 587
}
@dataclass
class WeeklyMetrics:
period_start: str
period_end: str
client_id: str
total_transactions: int
auto_classified: int
manually_corrected: int
flagged_for_review: int
new_vendors_encountered: int
accuracy_rate: float
exception_rate: float
top_misclassified_accounts: List[Dict]
top_misclassified_vendors: List[Dict]
accuracy_trend: str # 'improving', 'stable', 'declining'
alerts: List[str]
def calculate_accuracy(auto_correct: int, corrected: int, total: int) -> float:
if total == 0:
return 0.0
return auto_correct / total
def detect_trend(current_accuracy: float, previous_weeks: List[float]) -> str:
if len(previous_weeks) < 2:
return 'insufficient_data'
avg_previous = sum(previous_weeks[-3:]) / len(previous_weeks[-3:])
if current_accuracy > avg_previous + 0.02:
return 'improving'
elif current_accuracy < avg_previous - 0.02:
return 'declining'
return 'stable'
def analyze_misclassifications(corrections: List[Dict]) -> Dict:
"""Analyze correction patterns to identify systematic issues."""
account_errors = defaultdict(int)
vendor_errors = defaultdict(int)
common_swaps = defaultdict(int)
for c in corrections:
ai_account = c.get('ai_suggested_account', 'Unknown')
correct_account = c.get('corrected_to_account', 'Unknown')
vendor = c.get('vendor_name', 'Unknown')
account_errors[ai_account] += 1
vendor_errors[vendor] += 1
swap_key = f'{ai_account} -> {correct_account}'
common_swaps[swap_key] += 1
return {
'top_misclassified_accounts': sorted(
[{'account': k, 'error_count': v} for k, v in account_errors.items()],
key=lambda x: x['error_count'], reverse=True
)[:5],
'top_misclassified_vendors': sorted(
[{'vendor': k, 'error_count': v} for k, v in vendor_errors.items()],
key=lambda x: x['error_count'], reverse=True
)[:5],
'common_swaps': sorted(
[{'swap': k, 'count': v} for k, v in common_swaps.items()],
key=lambda x: x['count'], reverse=True
)[:5]
}
def generate_weekly_report(client_id: str, transactions: List[Dict], corrections: List[Dict], previous_accuracy: List[float]) -> WeeklyMetrics:
today = datetime.date.today()
week_start = today - datetime.timedelta(days=7)
total = len(transactions)
corrected = len(corrections)
flagged = len([t for t in transactions if t.get('status') == 'flagged'])
auto_correct = total - corrected - flagged
new_vendors = len(set(t.get('vendor_name') for t in transactions if t.get('is_new_vendor', False)))
accuracy = calculate_accuracy(auto_correct, corrected, total)
exception_rate = (corrected + flagged) / total if total > 0 else 0
trend = detect_trend(accuracy, previous_accuracy)
misclass = analyze_misclassifications(corrections)
alerts = []
if accuracy < MONITOR_CONFIG['accuracy_threshold_critical']:
alerts.append(f'CRITICAL: Classification accuracy {accuracy:.1%} is below {MONITOR_CONFIG["accuracy_threshold_critical"]:.0%} threshold')
elif accuracy < MONITOR_CONFIG['accuracy_threshold_warning']:
alerts.append(f'WARNING: Classification accuracy {accuracy:.1%} is below {MONITOR_CONFIG["accuracy_threshold_warning"]:.0%} threshold')
if exception_rate > MONITOR_CONFIG['exception_rate_threshold']:
alerts.append(f'WARNING: Exception rate {exception_rate:.1%} exceeds {MONITOR_CONFIG["exception_rate_threshold"]:.0%} threshold')
if trend == 'declining':
alerts.append('WARNING: Accuracy trend is declining over the past 3 weeks')
return WeeklyMetrics(
period_start=week_start.isoformat(),
period_end=today.isoformat(),
client_id=client_id,
total_transactions=total,
auto_classified=auto_correct,
manually_corrected=corrected,
flagged_for_review=flagged,
new_vendors_encountered=new_vendors,
accuracy_rate=accuracy,
exception_rate=exception_rate,
top_misclassified_accounts=misclass['top_misclassified_accounts'],
top_misclassified_vendors=misclass['top_misclassified_vendors'],
accuracy_trend=trend,
alerts=alerts
)
def format_report_email(metrics: WeeklyMetrics) -> str:
status = 'HEALTHY' if not metrics.alerts else 'ATTENTION NEEDED'
body = f"""
AI Transaction Classification — Weekly Report
================================================
Client: {metrics.client_id}
Period: {metrics.period_start} to {metrics.period_end}
Status: {status}
METRICS:
- Total transactions processed: {metrics.total_transactions}
- Auto-classified correctly: {metrics.auto_classified} ({metrics.accuracy_rate:.1%})
- Manually corrected: {metrics.manually_corrected}
- Flagged for review: {metrics.flagged_for_review}
- New vendors encountered: {metrics.new_vendors_encountered}
- Exception rate: {metrics.exception_rate:.1%}
- Accuracy trend: {metrics.accuracy_trend}
TOP MISCLASSIFIED ACCOUNTS:
{json.dumps(metrics.top_misclassified_accounts, indent=2)}
TOP MISCLASSIFIED VENDORS:
{json.dumps(metrics.top_misclassified_vendors, indent=2)}
ALERTS:
{'No alerts — system performing within expected parameters.' if not metrics.alerts else chr(10).join(' ⚠ ' + a for a in metrics.alerts)}
RECOMMENDED ACTIONS:
{'None required.' if not metrics.alerts else 'Review alerts above. Consider: updating classification rules for problematic vendors, reviewing CoA naming for ambiguous accounts, or scheduling a model retraining session with the bookkeeper.'}
"""
return body
# Entry point: Run weekly via cron
# 0 8 * * 1 python3 /opt/msp/classification_monitor.py
# For each client entity, pull data from Booke AI API + QBO/Xero, generate report, send email alertsNew Vendor Classification Prompt Template
Type: prompt
A standardized prompt template used when the AI classification engine encounters a vendor for the first time and needs to suggest an initial chart-of-accounts mapping. This prompt is designed to work with Booke AI's GPT-4 backend or can be used directly with OpenAI API for custom implementations. It provides context about the client's business type, chart of accounts, and transaction details to maximize first-attempt classification accuracy.
Implementation:
# New Vendor Classification Prompt Template
# Used when AI encounters a vendor not previously seen in the client's transaction history
# Variables in {brackets} are populated dynamically from the transaction and client context
SYSTEM_PROMPT = """
You are an expert bookkeeper classifying financial transactions for a {client_business_type} business.
Your task is to assign each transaction to the most appropriate account in the client's chart of accounts.
RULES:
1. You must select from ONLY the accounts listed below — never invent new accounts.
2. Consider the vendor name, transaction amount, and description to determine the correct account.
3. If the transaction could map to multiple accounts, choose the most specific one.
4. For ambiguous transactions, indicate low confidence so a human can review.
5. Never classify a transaction to an equity or liability account without high confidence.
6. Payroll-related transactions from known payroll providers (Gusto, ADP, Paychex) should map to Payroll Expense.
7. Revenue/income deposits should only map to revenue accounts if the source is clearly customer payments.
8. Bank transfers between the client's own accounts should be classified as 'Transfer' not as expense or income.
CLIENT'S CHART OF ACCOUNTS:
{chart_of_accounts_json}
RESPOND IN THIS EXACT JSON FORMAT:
{{
"account_code": "the account number",
"account_name": "the full account name",
"confidence": 0.0 to 1.0,
"reasoning": "brief explanation of why this account was selected",
"alternative_account": "second-best account if confidence < 0.85, otherwise null",
"flags": ["list of any concerns, e.g., 'possible_personal_expense', 'may_need_split', 'new_vendor'"]
}}
"""
USER_PROMPT = """
Classify this transaction:
- Vendor/Payee: {vendor_name}
- Amount: {amount} ({transaction_type})
- Date: {transaction_date}
- Description from bank: {bank_description}
- MCC Code (if available): {mcc_code}
- Bank Account: {bank_account_name}
Additional context:
- Client business type: {client_business_type}
- Client industry: {client_industry}
- Similar vendors previously classified:
{similar_vendor_classifications}
What account should this transaction be classified to?
"""
# Example populated prompt:
# SYSTEM: ... (with client's actual CoA)
# USER:
# Classify this transaction:
# - Vendor/Payee: CANVA PTY LTD
# - Amount: $155.88 (debit)
# - Date: 2025-01-10
# - Description from bank: CANVA PTY LTD SYDNEY AU
# - MCC Code: 5734 (Computer Software Stores)
# - Bank Account: Chase Business Checking
# Additional context:
# - Client business type: Marketing Agency
# - Client industry: Professional Services
# - Similar vendors previously classified:
# Adobe Inc -> 6210 Software & Technology (confidence: 0.98)
# Figma Inc -> 6210 Software & Technology (confidence: 0.95)
#
# Expected response:
# {
# "account_code": "6210",
# "account_name": "6210 - Software & Technology",
# "confidence": 0.95,
# "reasoning": "Canva is a graphic design SaaS platform. Similar to Adobe and Figma which are classified to Software & Technology. MCC code 5734 confirms software category.",
# "alternative_account": null,
# "flags": ["new_vendor"]
# }QBO Bank Rule Sync Automation
Type: integration
An integration script that synchronizes the deterministic classification rules from the YAML configuration file into QuickBooks Online's native Bank Rules feature. This ensures that rules work both through the custom rule engine AND through QBO's native bank feed interface, providing redundant classification coverage.
Implementation:
# QBO Bank Rule Sync Automation
# Reads classification rules from YAML config and creates/updates matching Bank Rules in QBO
# Uses QuickBooks Online API v3
# Requires: intuitlib, requests, pyyaml
import yaml
import requests
import json
from datetime import datetime
class QBOBankRuleSync:
BASE_URL = 'https://quickbooks.api.intuit.com/v3/company'
def __init__(self, realm_id: str, access_token: str, config_path: str):
self.realm_id = realm_id
self.access_token = access_token
self.headers = {
'Authorization': f'Bearer {access_token}',
'Accept': 'application/json',
'Content-Type': 'application/json'
}
with open(config_path, 'r') as f:
self.config = yaml.safe_load(f)
def get_accounts(self) -> dict:
"""Fetch chart of accounts to map names to QBO IDs."""
url = f'{self.BASE_URL}/{self.realm_id}/query'
query = "SELECT * FROM Account WHERE Active = true MAXRESULTS 200"
resp = requests.get(url, headers=self.headers, params={'query': query})
resp.raise_for_status()
accounts = resp.json().get('QueryResponse', {}).get('Account', [])
# Build lookup: account_name -> account_id
return {a['FullyQualifiedName']: a['Id'] for a in accounts}
def get_existing_rules(self) -> list:
"""Fetch existing bank rules from QBO."""
# Note: QBO API doesn't have a direct Bank Rules endpoint as of 2025.
# Bank rules are managed through the UI. This method is a placeholder
# for when API support is added, or can be replaced with Selenium automation.
# Current workaround: maintain a local mapping file of created rules.
try:
with open(f'/configs/clients/{self.config["client_id"]}/qbo_rules_map.json', 'r') as f:
return json.load(f)
except FileNotFoundError:
return []
def generate_rule_instructions(self) -> str:
"""Generate human-readable instructions for manual Bank Rule creation in QBO UI.
Since QBO API doesn't support Bank Rules programmatically, this generates
step-by-step instructions for the MSP technician to create rules manually.
"""
accounts = self.get_accounts()
instructions = []
instructions.append('=' * 60)
instructions.append('QBO BANK RULE CREATION INSTRUCTIONS')
instructions.append(f'Client: {self.config["client_name"]}')
instructions.append(f'Generated: {datetime.now().isoformat()}')
instructions.append('=' * 60)
instructions.append('')
instructions.append('Navigation: QBO > Banking > Rules > Add Rule')
instructions.append('')
for rule in self.config.get('rules', []):
conditions = rule.get('conditions', {})
action = rule.get('action', {})
if 'vendor_contains' not in conditions:
continue # Skip MCC-only rules (QBO doesn't support MCC in rules)
instructions.append(f'--- Rule: {rule["name"]} (ID: {rule["rule_id"]}) ---')
instructions.append(f' Apply to: {"Money Out" if conditions.get("transaction_type") == "debit" else "Money In"}')
for i, vendor_pattern in enumerate(conditions['vendor_contains']):
instructions.append(f' Condition {i+1}: Description CONTAINS "{vendor_pattern}"')
if 'amount_range' in conditions:
amt = conditions['amount_range']
if amt.get('min') and amt.get('max'):
instructions.append(f' Amount: Between ${amt["min"]} and ${amt["max"]}')
instructions.append(f' Assign to: Category = "{action.get("account", "UNSET")}"')
if action.get('class'):
instructions.append(f' Class: "{action["class"]}"')
if action.get('memo'):
instructions.append(f' Memo: "{action["memo"]}"')
auto_add = 'Yes' if action.get('auto_post', False) else 'No'
instructions.append(f' Automatically add: {auto_add}')
instructions.append('')
return '\n'.join(instructions)
# Usage:
# sync = QBOBankRuleSync(
# realm_id='1234567890',
# access_token='eyJ...',
# config_path='/configs/clients/acme-corp-001/classification_rules.yaml'
# )
# print(sync.generate_rule_instructions())
# Output: Step-by-step instructions for technician to create each rule in QBO UITesting & Validation
- BANK FEED CONNECTIVITY TEST: Verify all bank and credit card accounts show 'Connected' status in QBO/Xero. Manually reconcile the last 5 imported transactions against the bank statement to confirm amounts, dates, and vendor names are accurate. Document any discrepancies.
- BOOKE AI OAUTH CONNECTION TEST: In Booke AI dashboard, navigate to Integrations and verify the QBO/Xero connection shows 'Active' with a green indicator. Verify the chart of accounts is fully synced by comparing account count in Booke AI vs. QBO/Xero — they must match exactly.
- DEXT/HUBDOC OCR ACCURACY TEST: Upload 10 sample receipts (mix of restaurant receipts, office supply invoices, and utility bills) to Dext. Verify OCR extracts: vendor name (8/10+ correct), date (9/10+ correct), total amount (9/10+ correct), and tax amount (7/10+ correct). Document extraction errors.
- DEXT-TO-QBO PUBLISH TEST: Configure Dext to publish a test invoice to QBO in 'Draft' status. Verify the transaction appears in QBO with correct vendor, amount, date, and account coding. Delete the test transaction after verification.
- DETERMINISTIC RULE TEST: Create a test transaction matching Rule R001 (rent payment) conditions. Process it through the rule engine and verify it is classified to '6100 - Rent Expense' with auto_post=true and confidence=1.0. Repeat for 3 additional rules covering different conditions (vendor match, amount range, MCC code).
- AI CLASSIFICATION ACCURACY BASELINE: Export 50 historically classified transactions from QBO/Xero (already reviewed and confirmed correct by the bookkeeper). Re-process these through Booke AI and compare AI suggestions to the known-correct classifications. Target: 75%+ match rate on first pass before any training period.
- CONFIDENCE THRESHOLD TEST: Process 20 transactions through Booke AI and verify the confidence scoring: transactions with well-known vendors (e.g., Amazon, Starbucks) should score >85% confidence; transactions with obscure vendor names should score <70%. Verify that low-confidence items correctly route to the review queue.
- AUTO-POST SAFETY TEST: Set Booke AI to auto-post mode. Process 10 transactions from a test bank feed. Verify that: (a) high-confidence transactions post directly to the GL, (b) low-confidence transactions remain in the review queue, (c) transactions exceeding the $5,000 threshold are held for approval regardless of confidence.
- REWIND BACKUP AND RESTORE TEST: After auto-posting 10 test transactions, trigger a Rewind restore of the QBO file to the state before auto-posting. Verify all 10 transactions are removed and the GL balances revert correctly. This confirms the safety net works.
- SECURITY CONTROLS VALIDATION: Verify MFA is enabled on all QBO/Xero accounts (attempt login — MFA prompt must appear). Verify SentinelOne shows 'Protected' status on all bookkeeper workstations. Verify DNSFilter blocks access to a known test phishing domain (e.g., use DNSFilter's test page). Verify FortiGate IPS is active and logging.
- EXCEPTION HANDLING TEST: Introduce 5 intentionally ambiguous transactions (e.g., a generic 'PAYMENT' with no vendor info, a transfer between linked accounts, a refund transaction). Verify that the AI either classifies them correctly, routes them to the review queue, or flags them as exceptions — never silently misclassifies them.
- AUDIT TRAIL VERIFICATION: Process 10 transactions through the full pipeline (bank feed → rule engine → AI classification → GL posting). For each transaction, verify that a complete audit trail exists showing: original bank feed data, rule engine result (if matched), AI classification suggestion, confidence score, human review action (if any), and final posted account. Verify this trail is accessible in both Booke AI and QBO/Xero.
- END-TO-END MONTH CLOSE TEST: Simulate a mini month-end close by processing one week of transactions through the full automation pipeline. Have the client's bookkeeper review all AI-classified transactions, perform bank reconciliation, and confirm the trial balance. Measure: total bookkeeper time spent, number of corrections needed, and resulting accuracy rate. Compare to estimated time for manual classification of the same transactions.
- ROLE-BASED ACCESS TEST: Log in with each user role (Admin, Accountant, Standard User, View-Only) and verify that permissions are correctly enforced: Standard Users cannot modify the chart of accounts, View-Only users cannot post transactions, only Admins can modify Bank Rules and Booke AI settings.
Client Handoff
The client handoff meeting should be a 90-minute session with the firm owner/manager and lead bookkeeper(s), covering the following topics:
Documentation to Leave Behind:
- Quick Reference Guide (1-page laminated card with daily workflow steps)
- Classification Rules Registry (spreadsheet of all active rules with conditions and accounts)
- Chart of Accounts Master (clean, annotated version with account descriptions and usage guidelines)
- Security Checklist (monthly self-assessment checklist for FTC Safeguards compliance)
- Vendor Contact Sheet (MSP support, Booke AI support, QBO/Xero support, Dext support)
- Escalation Matrix (who to call for what: MSP for tech issues, Booke AI for classification issues, QBO for platform issues)
- Weekly Report Template (annotated example showing how to interpret accuracy metrics)
- Rewind Backup Restore Procedure (step-by-step instructions for emergency rollback)
Maintenance
Ongoing MSP Responsibilities:
Weekly (1-2 hours per client firm):
- Review Booke AI weekly accuracy report and classification metrics
- Verify all bank feed connections are active (check for disconnections)
- Review exception queue for systemic patterns that need new rules
- Verify Rewind daily backups completed successfully all 7 days
- Check SentinelOne endpoint status for all bookkeeper workstations
Monthly (2-4 hours per client firm):
- Generate and review monthly classification accuracy trend report
- Update deterministic rules for any new recurring vendors identified in the past month
- Review and adjust confidence thresholds if exception rate is too high (>15%) or too low (<3%)
- Verify all software subscriptions are active and not approaching expiration
- Apply OS and browser updates to all bookkeeper workstations
- Review Booke AI, Dext, and QBO/Xero release notes for new features or breaking changes
- Reconcile Booke AI account list against QBO/Xero chart of accounts (catch any manual CoA changes not reflected in AI layer)
Quarterly (4-6 hours per client firm):
- Conduct quarterly business review (QBR) with client firm: review accuracy metrics, time savings, ROI, and upcoming needs
- Full chart of accounts review — archive unused accounts, check for new duplicate patterns
- Review and update the client's WISP for FTC Safeguards Rule compliance
- Test Rewind restore procedure (restore a single transaction to verify backup integrity)
- Review vendor SOC 2 Type II reports for Booke AI, Dext, and any other third-party tools
- Reassess classification rules against actual transaction patterns — retire rules that no longer match and add rules for newly identified patterns
- Review user access lists — remove departed employees, verify role assignments
Annual:
- Full security audit aligned with FTC Safeguards Rule and IRS Pub 4557 requirements
- Renew all software licenses and renegotiate volume pricing
- Evaluate competitive landscape — assess whether current tool stack is still optimal or if better options have emerged
- Plan capacity for client growth (additional entities, higher transaction volumes)
Model Retraining Triggers (contact Booke AI support):
- Accuracy drops below 85% for 3 consecutive weeks
- Client undergoes significant business change (new revenue line, acquisition, industry pivot)
- Chart of accounts is significantly restructured (>10 accounts added, merged, or renamed)
- New bank accounts or credit cards added with different transaction patterns
SLA Considerations:
- Bank feed disconnection: Resolve within 4 business hours (critical — stops automation pipeline)
- AI classification error affecting financial statements: Resolve within 1 business day
- Security incident (compromised credentials, malware detection): Respond within 1 hour
- General configuration changes: Respond within 2 business days
- Monthly reporting: Delivered by 5th business day of following month
Escalation Path:
Want early access to the full toolkit?