What Vectis does with QuickBooks
- Syncs QBO customers to the Vectis
customerstable (auto-matched to existing PSA customers by name where possible). - Pulls invoices with total, balance, status, due date, and line-item currency into
billing_invoices. Invoice status is derived from balance + due date + VoidReason because QBO doesn’t expose a single status field. - Records payments with one row per payment-invoice settlement touch in
billing_payments. Unapplied on-account payments land as bare payment rows. - Tracks credit memos with balance + applied state in
billing_credit_memos. - Receives webhook events on invoice + payment updates into
quickbooks_webhook_eventsfor audit + replay (the audit row lands immediately;billing_*rows update on the next ETL tick).
What you'll need
- An Intuit developer-app Client ID + Client Secret registered at
developer.intuit.com→ My Apps. Both a sandbox app and a production app can share the same redirect URI — the environment is selected at connect time inside Vectis. - At least one QBO realm (company) the connecting operator has access to. Vectis supports one realm per integration row at this time.
- (Optional) A webhook verifier token from Intuit → My Apps → Webhooks. Required only if you want event audit rows in Vectis without waiting for the next ETL tick.
1. Register the Vectis app on Intuit
- Sign in at developer.intuit.com → My Apps with the Intuit account that owns the realm you want to sync.
- Click + Create an app. Pick QuickBooks Online and Payments. Scope:
com.intuit.quickbooks.accounting(read-only). - Open Keys & OAuth. Set the redirect URI to the value Vectis shows in Admin → Integrations → QuickBooks. Match character-for-character.
- Copy the Client ID and Client Secret for both the sandbox and production sections. The secret is shown only once after rotation.
2. Connect QuickBooks in Vectis
- In Vectis, go to Admin → Integrations → QuickBooks and click Connect QuickBooks (Sandbox). The browser is redirected to Intuit’s consent screen.
- Sign in to the sandbox company and grant the Vectis app the requested scope. Intuit redirects back to Vectis with a
realmId+ access token. Vectis persists the encrypted token pair and flips the connection state to Connected. - Confirm the realm ID, environment (Sandbox), and Days until refresh expiry render correctly. Trigger a manual sync from the integrations page; verify customers / invoices / payments rows land tagged
source = ‘quickbooks’. - Once sandbox passes end-to-end, repeat the connect flow with production credentials. The connection record is replaced (one realm per provider per tenant), so disconnect first if you want to keep sandbox + production wired side-by-side on different Vectis tenants.
3. (Optional) Wire webhooks
- In Intuit → My Apps → Webhooks, register a subscription pointing at
https://<your-vectis-host>/api/webhooks/quickbooks. Subscribe to Invoice + Payment events at minimum. - Copy the verifier token Intuit shows. Paste it into the Vectis setup page’s Webhook verifier token field and save.
- Trigger a test event on the Intuit side. Vectis verifies the HMAC-SHA256 signature and inserts one row per
eventNotificationintoquickbooks_webhook_events. Duplicate deliveries are silently no-oped via the(realm_id, qbo_event_id)unique index.
What appears where
- Customer hub → Billing section: invoiced this month, outstanding balance, contracted MRR, recent invoices. Renders alongside Xero rows on the same panel —
sourceis transparent at the UX level. - Alerts: feeds the
invoice_overduetrigger (balance > min, due date past) and the flagshipservice_without_invoicetrigger (resolved tickets in window with zero invoices issued in the same window for that customer). - Customer timeline: invoice + payment events attach to the customer’s timeline alongside PSA tickets and RMM alerts.
Limits and caps
- Refresh token lifetime: 100 days from issue (Intuit’s published cap). Vectis warns at 14 days + 3 days before expiry — reconnect on the setup page before the cutoff or the token is invalidated and you’ll need to re-consent.
- Rate limit: Vectis defaults to 5 req/sec (300 req/min) per realm, well under Intuit’s 500/min cap.
- Pagination: 500-row pages, 200-page hard cap. A bad WHERE clause can’t runaway-scan a realm.
- Currency: invoice currency is stored verbatim per row. FX normalisation to a reporting currency is downstream margin-engine work.
- Read-only: this phase does not create invoices, send invoices, or record payments. Those write verbs are deferred to a future phase on dedicated rule actions like
create_quickbooks_invoice(mirroring the Datto restore pattern).
Common errors
401 Unauthorized — the access token has expired and a refresh failed (most often because the refresh token also expired, or because another caller already rotated it). Click Disconnect + Connect QuickBooks again to re-consent.
403 Forbidden — the realm no longer grants the requested scope, or you’re using sandbox credentials against a production realm (or vice-versa). Confirm the environment matches and reconnect if needed.
Webhook 401 — the verifier token in Vectis doesn’t match the one Intuit is signing with. Re-copy from Intuit → My Apps → Webhooks and paste again.
Webhook 200 but no rows — the body parsed but the event was a duplicate of one already recorded. The (realm_id, qbo_event_id) unique index de-duplicates Intuit’s retry cascade.