diff --git a/.planning/STATE.md b/.planning/STATE.md
index 1ad7600..faa322e 100644
--- a/.planning/STATE.md
+++ b/.planning/STATE.md
@@ -28,7 +28,7 @@ See: .planning/PROJECT.md (updated 2026-07-14)
Phase: Milestone v3.0 complete
Plan: —
Status: Awaiting next milestone
-Last activity: 2026-07-18 — Completed quick task 260718-7v8: Mimecast blast-radius held-message false-positive fix
+Last activity: 2026-07-18 — Completed quick task 260718-9qg: QBO integration handoff document
## Performance Metrics
@@ -129,6 +129,7 @@ None yet.
| 260717-a19 | Fix phishing simulation-vendor allowlist gaps (3 missing KnowBe4 domains), auto-parse timing race (retry on ticket.update), and parseAndStoreMessage idempotency; reclassified 6 stale Seubert campaigns (all flipped UNWANTED → USER_AWARENESS) | 2026-07-17 | cf04f07 | [260717-a19-fix-phishing-simulation-vendor-allowlist](./quick/260717-a19-fix-phishing-simulation-vendor-allowlist/) |
| 260717-v6c | Add "Mark as accidental report" action to the phishing Action Area — closes out a campaign and posts a fixed customer-facing note to the reporter (distinct from the silent "Mark as false positive" action) | 2026-07-18 | 565a0c1 | [260717-v6c-add-a-mark-as-accidental-report-action-t](./quick/260717-v6c-add-a-mark-as-accidental-report-action-t/) |
| 260718-7v8 | Fix Mimecast blast-radius false positives — date-scope `getHeldMessages()` and add a sender-domain relevance guard so unrelated held mail in a recipient's queue no longer inflates held/matched counts or overwrites a genuinely delivered recipient's status | 2026-07-18 | b7d6be4 | [260718-7v8-fix-mimecast-blast-radius-held-message-f](./quick/260718-7v8-fix-mimecast-blast-radius-held-message-f/) |
+| 260718-9qg | Add self-contained `QBO_INTEGRATION_HANDOFF.md` documenting Pulse's QuickBooks Online OAuth2 flow, token storage/refresh, sandbox/production API base URLs, and gotchas (deletion-diffing, CSRF state gap, NEXTAUTH_URL legacy var) for a new app's team | 2026-07-18 | ea8a36b | [260718-9qg-create-a-quickbooks-online-integration-h](./quick/260718-9qg-create-a-quickbooks-online-integration-h/) |
## Deferred Items
diff --git a/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-PLAN.md b/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-PLAN.md
new file mode 100644
index 0000000..3af1514
--- /dev/null
+++ b/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-PLAN.md
@@ -0,0 +1,109 @@
+---
+phase: quick-260718-9qg
+plan: 01
+type: execute
+wave: 1
+depends_on: []
+files_modified: [QBO_INTEGRATION_HANDOFF.md]
+autonomous: true
+requirements: [DOC-QBO-HANDOFF]
+must_haves:
+ truths:
+ - "A reader with NO access to the Pulse codebase can understand Pulse's QBO integration end to end from this one file"
+ - "The full OAuth2 authorization-code flow is documented step by step (authorize → callback → token exchange → storage → refresh)"
+ - "Env vars, API base URLs (sandbox vs production), scopes, and minor version are stated explicitly"
+ - "Known gotchas — including anything learned from the recent QBO AR diagnostics work — are captured"
+ artifacts:
+ - path: "QBO_INTEGRATION_HANDOFF.md"
+ provides: "Self-contained QBO integration handoff document for a new app"
+ min_lines: 120
+ key_links: []
+---
+
+
+Produce a single standalone markdown document, `QBO_INTEGRATION_HANDOFF.md` at the repo root, that captures everything Pulse knows about connecting to QuickBooks Online (QBO), so a separate new application's team — who will NOT have access to the Pulse codebase — can implement their own QBO integration with a head start.
+
+Purpose: Transfer hard-won integration knowledge (OAuth2 flow, token storage/refresh, API base URLs, scopes, gotchas) to a team building a brand-new app.
+Output: `QBO_INTEGRATION_HANDOFF.md` (new file, repo root).
+
+**Docs-only task.** No application source code may be modified. The only file written is the handoff document.
+
+
+
+@$HOME/.claude/get-shit-done/workflows/execute-plan.md
+@$HOME/.claude/get-shit-done/templates/summary.md
+
+
+
+@.planning/STATE.md
+
+Known QBO surface in this repo (starting points for the executor's investigation — the executor MUST read these, not assume their contents):
+- `lib/services/qbo-client.ts` — QBO API client (expect factory pattern per repo convention: `getQboClient()` / `isQboConfigured()`)
+- `lib/services/qbo-sync-service.ts` — sync service (invoices, AR, etc.)
+- `app/api/qbo/auth/route.ts` — OAuth2 connect/authorize + callback handling
+- `app/api/qbo/sync/route.ts` — sync trigger endpoint
+- `app/api/qbo/disconnect/route.ts` — token teardown
+- `app/api/qbo/diagnose-ar/route.ts` — AR (accounts receivable) diagnostics (likely source of recently-learned gotchas)
+- `migrations/051_create_qbo_tables.sql` — QBO tables (token storage, invoices, etc.)
+- `migrations/088_qbo_invoices_soft_delete.sql` — soft-delete addition
+- No existing QBO guide under `docs/` — this handoff is net-new.
+- Note: `.env` did NOT surface `QBO_*` / `QUICKBOOKS_*` / `INTUIT_*` vars by name — the executor MUST grep the source for `process.env.` inside the QBO files to discover the ACTUAL env var names in use.
+
+
+
+
+
+ Task 1: Investigate Pulse's QBO integration and write the self-contained handoff doc
+ QBO_INTEGRATION_HANDOFF.md
+
+First, INVESTIGATE the existing QBO integration in this repo. Do not write anything until the investigation is complete. Read (not skim) each of the following and extract the concrete details:
+
+1. Env vars — grep the QBO files for `process.env.` to find the REAL variable names, then record each: client id, client secret, environment (sandbox vs production toggle), redirect/callback URI, realm/company id, and any discovery or token endpoint overrides. Command hint: `grep -rn "process\.env\." lib/services/qbo-client.ts lib/services/qbo-sync-service.ts app/api/qbo/`.
+
+2. OAuth2 authorization-code flow — from `app/api/qbo/auth/route.ts` and `lib/services/qbo-client.ts`, capture: the authorize URL (Intuit `appcenter.intuit.com/connect/oauth2`), the requested scopes (e.g. `com.intuit.quickbooks.accounting`), the `state` handling / CSRF protection, the redirect URI, the token-exchange URL (`oauth.platform.intuit.com/oauth2/v1/tokens/bearer`), the token-refresh flow, and how the `realmId` (company id) is received on the callback.
+
+3. Token storage — from `migrations/051_create_qbo_tables.sql` (and `088`), document the exact table(s) and columns used to persist access token, refresh token, realm/company id, and expiry timestamps; and from the client code, how expiry is detected and refresh is triggered (proactive vs on-401).
+
+4. API base URLs & versioning — record the sandbox base (`sandbox-quickbooks.api.intuit.com`) vs production base (`quickbooks.api.intuit.com`), the `minorversion` query param if used, and the request path shape (`/v3/company/{realmId}/...`).
+
+5. What QBO is used for in Pulse — read `lib/services/qbo-sync-service.ts` and the api routes to summarize the entities synced (invoices, AR, payments/deposits) and the direction of data flow.
+
+6. Gotchas / lessons learned — read `app/api/qbo/diagnose-ar/route.ts` and run `git log --oneline -20 -- app/api/qbo lib/services/qbo-client.ts lib/services/qbo-sync-service.ts migrations/051_create_qbo_tables.sql migrations/088_qbo_invoices_soft_delete.sql` (and inspect the "QBO AR diagnostics" work referenced in the recent `chore: check in pending work` commit) to fold in any real gotchas: rate limits, token-refresh failures, sandbox-vs-production quirks, AR/invoice reconciliation issues, soft-delete handling, realm mismatch, etc. Also check the completed quick-task dirs under `.planning/quick/` matching `*qbo*` (e.g. `260519-0oz-add-qbo-createpayment-createdeposit`, `260521-fci-stopgap-nightly-reconciliation`) for SUMMARY notes worth distilling.
+
+Then WRITE `QBO_INTEGRATION_HANDOFF.md` at the repo root as a self-contained document. It MUST be readable by someone with zero access to this codebase: inline every relevant detail; do NOT leave bare "see lib/services/qbo-client.ts" pointers — if a detail lives in a Pulse file, summarize the detail itself. Pulse file paths may appear only as parenthetical "(in Pulse this lives in …)" provenance notes, never as the sole carrier of information.
+
+Structure the document roughly as:
+- **Overview** — what QBO integration does and why (the business purpose).
+- **Prerequisites** — creating an Intuit Developer app, sandbox vs production, redirect URI registration, required scopes.
+- **Environment variables** — a table of every env var (real names discovered from source) with description and example/placeholder value. Do NOT copy any real secret values from `.env`; use placeholders.
+- **OAuth2 connection flow** — a numbered, step-by-step walkthrough: authorize redirect → user consent → callback with `code` + `realmId` → token exchange → persistence → subsequent refresh. Include the exact Intuit URLs.
+- **Token storage & refresh** — the table schema (columns + purpose) and the refresh strategy, generalized so the new app can adapt it (they may not use Postgres).
+- **API usage** — base URLs (sandbox/production), path shape, minor version, an example authenticated request.
+- **Gotchas & lessons learned** — the concrete pitfalls gathered in the investigation.
+- **Minimal code-flow example** — a distilled, framework-agnostic pseudocode/TypeScript sketch of authorize → exchange → refresh → call (NOT a copy-paste of Pulse code; enough that a QBO-unfamiliar team can implement their own).
+
+Write directive prose and generalized examples. Do NOT modify any application source, migrations, env files, or existing docs.
+
+
+ test -f QBO_INTEGRATION_HANDOFF.md && test $(grep -v '^#' QBO_INTEGRATION_HANDOFF.md | wc -l) -ge 100 && grep -qi 'oauth' QBO_INTEGRATION_HANDOFF.md && grep -qi 'refresh' QBO_INTEGRATION_HANDOFF.md && grep -qiE 'sandbox|production' QBO_INTEGRATION_HANDOFF.md && echo OK
+
+
+`QBO_INTEGRATION_HANDOFF.md` exists at repo root, is self-contained (no information-bearing bare file-path pointers), and covers overview, prerequisites, env vars, the full OAuth2 flow, token storage/refresh, API base URLs (sandbox + production), gotchas, and a minimal code-flow example. No application source, migration, env, or existing doc files were modified.
+
+
+
+
+
+
+- `git status` shows exactly one new file (`QBO_INTEGRATION_HANDOFF.md`) and no modifications to existing tracked source/docs/migrations.
+- The document contains no real secret values (placeholders only).
+- Every major section (overview, prerequisites, env vars, OAuth2 flow, token storage/refresh, API URLs, gotchas, code example) is present and populated with concrete detail drawn from the repo investigation.
+
+
+
+A new-app engineer can read `QBO_INTEGRATION_HANDOFF.md` alone and understand how to register an Intuit app, run the OAuth2 authorization-code flow, store and refresh tokens, hit the correct sandbox/production API endpoints, and avoid the pitfalls Pulse already hit — without ever opening the Pulse codebase.
+
+
+
diff --git a/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-SUMMARY.md b/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-SUMMARY.md
new file mode 100644
index 0000000..080f50a
--- /dev/null
+++ b/.planning/quick/260718-9qg-create-a-quickbooks-online-integration-h/260718-9qg-SUMMARY.md
@@ -0,0 +1,92 @@
+---
+phase: quick-260718-9qg
+plan: 01
+subsystem: docs
+tags: [quickbooks, qbo, oauth2, integration, handoff, finance]
+
+# Dependency graph
+requires: []
+provides:
+ - "QBO_INTEGRATION_HANDOFF.md — self-contained OAuth2/token/API/gotchas reference for QuickBooks Online, written for a team with no access to Pulse's codebase"
+affects: [any future work building or maintaining a QBO integration in a different app]
+
+# Tech tracking
+tech-stack:
+ added: []
+ patterns: []
+
+key-files:
+ created:
+ - QBO_INTEGRATION_HANDOFF.md
+ modified: []
+
+key-decisions:
+ - "Inlined every detail (env vars, exact Intuit URLs, table schemas, request/response shapes) rather than pointing at Pulse source files, per the plan's self-containment requirement"
+ - "Called out two real defects found during investigation as explicit gotchas rather than silently working around them: unverified OAuth `state` (CSRF gap) and the legacy `NEXTAUTH_URL` env var used for the redirect URI instead of Pulse's actual BETTER_AUTH_URL"
+ - "Used placeholder values for all env var examples — no real secrets existed in .env for QBO_* keys to begin with, so nothing needed redaction"
+
+requirements-completed: [DOC-QBO-HANDOFF]
+
+# Metrics
+duration: 25min
+completed: 2026-07-18
+---
+
+# Phase quick-260718-9qg Plan 01: QBO Integration Handoff Doc Summary
+
+**Self-contained `QBO_INTEGRATION_HANDOFF.md` covering QBO's OAuth2 authorization-code flow, token storage/refresh schema, sandbox vs production API base URLs, minor-version pinning, and 11 concrete gotchas (deletion-diffing, CSRF state, report NoReportData markers, check-number normalization, idempotency, etc.) drawn from Pulse's actual QBO source and its recent AR-reconciliation fix.**
+
+## Performance
+
+- **Duration:** ~25 min
+- **Started:** 2026-07-18T11:00:00Z (approx.)
+- **Completed:** 2026-07-18T11:25:00Z (approx.)
+- **Tasks:** 1
+- **Files modified:** 1 (new file)
+
+## Accomplishments
+- Investigated Pulse's real QBO integration end to end: `lib/services/qbo-client.ts`, `lib/services/qbo-sync-service.ts`, all four `app/api/qbo/*` routes, `migrations/051_create_qbo_tables.sql`, `migrations/088_qbo_invoices_soft_delete.sql`, `middleware.ts` public-route list, `integration-health.ts` config check, git history (`b98c674`, `ef9b31e`, `672f17b`), and the `260519-0oz` quick-task SUMMARY for the createPayment/createDeposit work.
+- Wrote `QBO_INTEGRATION_HANDOFF.md` (596 lines) at the repo root with all required sections: Overview, Prerequisites, Environment variables (table), OAuth2 connection flow (11-step numbered walkthrough with exact Intuit URLs), Token storage & refresh (generalized schema + pseudocode), API usage (base URLs, path shape, minorversion, query/write/report examples), Gotchas & lessons learned (11 concrete items), and a framework-agnostic TypeScript pseudocode code-flow example.
+- Surfaced two real defects discovered during investigation as explicit gotchas for the new team to avoid repeating: (1) Pulse's OAuth `state` value is generated but never persisted/verified on callback — a real CSRF gap; (2) the redirect-URI base URL is read from `NEXTAUTH_URL`, a variable not present anywhere in Pulse's `.env`/`.env.local` (a legacy holdover from a prior auth library), distinct from the app's actual `BETTER_AUTH_URL`.
+
+## Task Commits
+
+Each task was committed atomically:
+
+1. **Task 1: Investigate Pulse's QBO integration and write the self-contained handoff doc** - `ea8a36b` (docs)
+
+**Plan metadata:** (this commit, made after SUMMARY.md)
+
+## Files Created/Modified
+- `QBO_INTEGRATION_HANDOFF.md` - Self-contained QBO integration handoff document (overview, prerequisites, env vars, OAuth2 flow, token storage/refresh, API usage, gotchas, code-flow example)
+
+## Decisions Made
+- Inlined every Pulse-derived detail directly into the doc (no bare `see lib/services/qbo-client.ts` pointers); Pulse file paths appear only as parenthetical provenance notes.
+- Documented the `NEXTAUTH_URL` / `BETTER_AUTH_URL` mismatch and the unverified OAuth `state` as explicit "don't repeat this" gotchas rather than omitting them, since the plan's objective is transferring hard-won (including negative) knowledge to a new team.
+- Recommended `crypto.randomUUID()` (or a signed token) plus server-side verification in place of Pulse's current `Math.random()`-based `state`, and recommended adding an explicit Intuit token-revocation call for a real "disconnect," since a new implementation should start from a stronger baseline than Pulse's current code.
+
+## Deviations from Plan
+
+None - plan executed exactly as written. This was a docs-only investigation-and-write task; no application source, migrations, env files, or existing docs were touched (confirmed via `git status --short`, which shows only `QBO_INTEGRATION_HANDOFF.md` as an addition).
+
+## Issues Encountered
+None.
+
+## User Setup Required
+
+None - no external service configuration required. This task only produced a reference document; it does not change any running behavior.
+
+## Next Phase Readiness
+- `QBO_INTEGRATION_HANDOFF.md` is ready to be handed directly to the new application's engineering team.
+- No blockers. If the new team later reports gaps (e.g. QBO Payments/charge-card scope, multi-realm support), a follow-up quick task can extend this document — it was intentionally scoped to what Pulse's own integration actually covers (accounting scope only, single realm).
+
+## Self-Check: PASSED
+
+- `QBO_INTEGRATION_HANDOFF.md` exists at repo root — FOUND
+- Automated verify command (`test -f ... && line count >= 100 && grep oauth/refresh/sandbox|production`) — PASSED (`OK`)
+- Commit `ea8a36b` exists in git log — FOUND
+- `git status --short` shows only `QBO_INTEGRATION_HANDOFF.md` as a tracked addition (plus the pre-existing untracked `.planning/quick/260718-9qg-.../` plan directory, unrelated to source/docs/migrations) — CONFIRMED
+
+---
+*Phase: quick-260718-9qg*
+*Completed: 2026-07-18*