How QuickBooks Online (QBO) Integration Works
Source: quickbooks_online_controller.rb, company_accounting_setting.rb
- SSO token is a UUID combined with a timestamp; during company lookup, the system checks multiple regional servers to find the matching company
- The first QBO user created on a company is automatically assigned; when shares_account is true, tokens are shared across all branches in the group
- OAuth2 redirect_uri always uses the AU (Australian) domain on production, regardless of the customer's actual region
- Sign-up validation requires exactly 1 user on the company and fewer than 2 QBO users total
- Tax rate resolution walks through effective dates to find the currently active rate — historical rates on old invoices may differ
- If no customers or vendors have QBO IDs, the system flags ALL contacts for re-sync — this can trigger a massive re-upload on first sync or after a bulk clear
- "Clear duplicates" removes customer/vendor records where the same QBO ID is shared by multiple Workshop records
- QBO access is determined solely by whether the token field is non-blank — there is NO expiry check, so a token could be expired but still appear "connected"
Support scenarios
- "QBO shows as connected but sync keeps failing" → QBO access is checked only by whether a token exists, not whether it's still valid. The token may be expired. Re-authenticate to get a fresh token.
- "After clearing contacts, the sync is trying to upload thousands of records" → When no contacts have QBO IDs, the system flags ALL contacts for re-sync. This is expected after a bulk clear but can cause timeouts or rate limiting. Let it run through in batches.
- "QBO redirect isn't working for our region" → The OAuth2 redirect always points to the AU domain on production. If there's a redirect issue, it's likely a configuration or firewall problem, not a region mismatch — the AU domain is intentional.
- "We have duplicate customers in QBO" → Use the "Clear duplicates" tool which removes Workshop records where multiple records share the same QBO ID, keeping the data clean for the next sync.