ServicesWorkProcessBlogContactBook a call
← All postsSep 11, 2026 · case study · infrastructure

How we built a bookkeeping agent that files nothing on its own

The problem

Month-end for a small Canadian business is hours of the same work: reconcile the bank feed, figure out which payment cleared which invoice, prepare the HST return, assemble a year-end package for the accountant, run payroll. QuickBooks Online already holds the truth — the work is moving numbers around it and checking them.

The design principle

QBO stays the system of record. The agent reads from it and writes back reconciled entries; it does not replace it or keep a shadow ledger. And nothing that moves money or files with a government submits itself — every such action is staged for a human to approve.

Architecture

The system is serverless and event-driven on AWS. It wakes on three triggers: a new bank transaction lands (webhook), a daily matching sweep (schedule), and the monthly / quarterly / annual cadences for HST and corporate tax.

  • Amazon Bedrock (Claude) handles the judgment calls — categorization, ambiguous matches, anomaly detection — and always returns its reasoning.
  • Step Functions orchestrates each multi-step workflow.
  • DynamoDB holds staging tables (unmatched transactions, confidence scores, approval status) and an immutable audit log.
  • Textract OCRs scanned invoices and receipts.
  • SES sends digest emails and one-click approval requests.
  • Secrets Manager holds the QBO OAuth tokens; IAM scopes each Lambda to least privilege (the reconciliation function is read-only against QBO).

Reconciliation

  • Exact match — amount plus date within a couple of days plus an already-categorized QBO entry — auto-reconciles with no review.
  • Fuzzy match — amount matches but the description differs (a processor deposit net of fees, say) — Claude proposes the match with its reasoning and it goes to a one-click approval queue.
  • No match — a genuinely new transaction — gets a category suggestion drawn from historical patterns and is created in QBO as "for review," never posted uncategorized.
  • Duplicate feeds and transactions that should be split across GL accounts are flagged.

Invoice and payment matching

Separate from bank reconciliation, this closes the loop between documents and cash. Incoming deposits are matched to open QBO invoices by customer, amount, and date window (handling partial payments and early-payment discounts); outgoing payments are matched to open bills, catching duplicate vendor payments before they go out. OCR'd source documents are attached to the matched transaction for the audit trail.

HST and corporate tax prep

CRA does not offer a public API to file GST/HST returns, so this module gets the return filing-ready and stops there. It pulls HST collected and input tax credits straight from QBO's sales-tax reports, cross-checks that every taxable transaction carries the right tax code, and produces a worksheet mapped to the CRA GST34 lines — line 101 (sales), 105 (HST collected), 108 (ITCs), and the net. [verify: GST34 line numbers against the current CRA GST34 form.] For year-end it generates a clean financials package — P&L, Balance Sheet, Trial Balance, GL detail — formatted for the accountant's tax software, with book-to-tax adjustment candidates flagged. A licensed accountant reviews and files.

Payroll — the highest-stakes part

Payroll moves real money to real people under strict statutory rules, so the design is: the agent prepares and validates every pay run, and release of funds needs explicit approval each cycle. It tracks hours, salary changes, new hires and terminations; computes statutory deductions (CPP, EI, federal and provincial withholding); tracks employer remittances and their due dates; and runs a variance check against the prior run. It runs in shadow mode — calculating but not paying — for a full cycle before going live. On approval it triggers the pay run and posts the journal entry back to QBO. If approval is not received by a cutoff, it escalates rather than silently running or silently missing payroll.

Guardrails

Bedrock Guardrails constrain the model to act only on tool-returned QBO and bank data, never invent figures, and always show its match rationale. Banking credentials and employee SIN / compensation data are encrypted at the field level. Every automated action writes an immutable audit-log entry — who, what, when, why — for internal control and CRA audit defense. A separate monthly activity report summarizes what the agent did.

What it costs to run

Roughly $20–50 per month for a single company file: Lambda and Step Functions under $2, Bedrock $10–30 depending on volume, DynamoDB and S3 $2–5, Textract about $1.50 per thousand pages, SES under $1. That excludes the QuickBooks Online and any payroll-processor subscriptions.

How we rolled it out

Reconciliation MVP first, validated against months of historical data before it touched a live transaction. Then invoice/payment matching with Textract. Then the approval and notification layer. Then HST prep, run in parallel with the existing process and compared. Then payroll in shadow mode for a full cycle. Then the year-end package, reviewed with the accountant before the filing deadline. A staging QBO sandbox company throughout.

This is the kind of system we build

If your team is doing this by hand every month, book a call.

Publishing note: this is a summary of a real engagement. No client name and no AWS account identifiers appear here by design. Verify CRA / QBO specifics before publishing.

Book a callMore posts