QuickBooks Online Sync — Setup Guide
Sync your Salesforce customers, products, and invoices to QuickBooks Online — and see payment status flow back automatically.
On this page ▾
✦Before you start — is this connector right for you?
| Requirement | Why |
|---|---|
| QuickBooks Online (not Desktop) | The connector uses the QBO REST API. |
| A US / USD company file | This version supports US, USD-based QuickBooks companies only. A non-USD company is refused at connection time (Step 5) so your books can't post in the wrong currency. |
| Salesforce Enterprise, Unlimited, or Developer | Needs API access and Named Credentials. |
| An Intuit Developer account | You create your own QuickBooks app — free. Step 2. |
| System Administrator in Salesforce | Setup requires Setup access and permission-set assignment. |
Start in a QuickBooks sandbox. Do a full dry run against a QuickBooks sandbox company before pointing at your live books. Every step below works identically in sandbox.
1Assign permission sets
The package ships three permission sets. Assign based on role:
| Permission set | Give to | Grants |
|---|---|---|
| Integration OS Admin | You / integration admins | Configure connections, profiles, mappings; the admin console |
| QuickBooks Integration | You / integration admins | The QBO_* fields on Account, Contact, Opportunity, Product2 |
| Integration OS User | Sales / ops users who trigger syncs | Run a sync, see results — read-only on configuration |
An admin needs both Integration OS Admin and QuickBooks Integration. The first grants the configuration objects; the second grants the QuickBooks Id fields on your business records. With only the first, you'll configure syncs but won't see the QuickBooks Ids on your Accounts and Opportunities.
Setup → Permission Sets → select each → Manage Assignments → Add Assignment.
A fourth, optional set — Integration OS - Bypass Validation — lets your integration user skip specific validation rules on inbound syncs. Assign it only if you need that; see Validation rules & the integration user.
2Create your QuickBooks (Intuit) app
You connect Salesforce to QuickBooks with your own Intuit app. (Each company uses its own, so your credentials are never shared.)
- Go to developer.intuit.com → sign in → Dashboard → Create an app.
- Choose QuickBooks Online and Payments, scope
com.intuit.quickbooks.accounting. - Open Keys & credentials. Use the Development keys for your dry run; switch to Production keys when you go live. Copy the Client ID and Client Secret.
- Under Redirect URIs, add exactly (replace
MyDomainwith your Salesforce My Domain):
No trailing slash. This must match Step 3 character-for-character, or authorization fails withhttps://MyDomain.my.salesforce.com/services/authcallback/QuickBooksinvalid_redirect_uri.
Development and Production keys are not interchangeable — production keys against a sandbox company (or vice-versa) fail with a confusing error.
3Connect Salesforce to QuickBooks
3a · Auth Provider
Setup → Auth. Providers → New → Type: OpenID Connect (or use the packaged QuickBooks Auth Provider if present and just fill in the keys):
| Field | Value |
|---|---|
| Name / URL Suffix | QuickBooks (must be exactly this — it forms the redirect URI) |
| Consumer Key | your Client ID (Step 2) |
| Consumer Secret | your Client Secret (Step 2) |
| Authorize Endpoint | https://appcenter.intuit.com/connect/oauth2 |
| Token Endpoint | https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer |
| Default Scopes | com.intuit.quickbooks.accounting openid |
Enable Use PKCE (recommended by Intuit). Save.
3b · Confirm the callback URL
After saving, the Auth Provider shows a Callback URL. Confirm it matches what you registered in Step 2. If different, correct the Intuit Redirect URI to match.
3c · External Credential + Named Credential
The package provides QuickBooks Online External and Named Credentials (or create them):
- External Credential
QuickBooks_Online— Authentication Protocol OAuth 2.0, Named Principal, referencing the QuickBooks Auth Provider above. - Named Credential
QuickBooks_Online— URL:- Sandbox:
https://sandbox-quickbooks.api.intuit.com - Production:
https://quickbooks.api.intuit.com
- Sandbox:
3d · Authorize
On the External Credential → Principals → the named principal → dropdown → Authenticate. Sign in to QuickBooks, choose your company, approve the scopes. Status should read Authenticated.
3e · Grant the principal
On both Integration OS Admin and Integration OS User permission sets, confirm the External Credential Principal Access for QuickBooks_Online is enabled. (The packaged sets already include this.)
Without this grant, syncs fail authorization even though the connection shows Authenticated — the single most common setup snag.
4Create the connection record
Open the Integration OS Admin Console (App Launcher → Admin Console) → Connections, or create an External System record:
| Field | Value |
|---|---|
| Name | QuickBooks Online |
| System Type | QuickBooks |
| Named Credential | QuickBooks_Online |
| Company / Realm ID | your QuickBooks Company ID (Intuit → your company → Settings → Additional info → Company ID) |
| Topology | Cloud |
| Health Check Path | /v3/company/{company}/companyinfo/{company}?minorversion=70 |
| Guard Response Path | CompanyInfo.Country |
| Guard Expected Value | US |
| Active | ✓ |
The last two fields enforce the USD / US-only boundary.
5Test the connection
In the console, Connections → Test connection (or Test Connection on the record).
| Result | Meaning |
|---|---|
| Healthy | Connected, US company — you're good. |
| Unsupported | Reachable, but not a US company — this version is USD / US only. Stop here. |
| Auth-Failed | Token expired or wrong secret — re-authenticate (Step 3d). |
| Down | Unreachable — check the Named Credential URL and realm Id. |
A connection marked Unsupported is blocked from syncing on purpose — it prevents posting against the wrong currency.
6Install the default sync profiles
Rather than building sync configuration by hand, install the shipped defaults. Console → Connections → your connection → Install QuickBooks defaults. This creates four inactive sync profiles:
| Profile | What it does | Ships |
|---|---|---|
| Account → QuickBooks Customer | Push accounts as customers | Create + update |
| Product2 → QuickBooks Item | Push products as items | Create only |
| Opportunity → QuickBooks Invoice | Push opportunities as invoices (with lines) | Create only |
| QuickBooks Invoice → Opportunity (Payment Reconciliation) | Pull invoice balances back | Update only |
They arrive inactive with safe defaults — invoices are create-only (a posted invoice is a financial document; you enable updates deliberately, if ever). Review before activating (Step 9).
7Point the Item profile at your income account
This is the one value the connector can't guess — your chart of accounts is unique to your company.
- Sync your chart of accounts: the console has a Chart of Accounts reference pull, or run the QuickBooks Chart of Accounts → External Reference profile once. Your accounts appear as External Reference records.
- On the Product2 → QuickBooks Item profile, open the
IncomeAccountRef.valuefield mapping → set Reference Value to the income account you want (e.g. Sales of Product Income), chosen from the synced list.
QuickBooks rejects an Item with no income account, so this must be set before syncing items.
8Prepare your data (external Id fields)
The connector tracks what's synced using QBO_* Id fields on your records (populated automatically on first sync): Account.QBO_Customer_Id__c, Product2.QBO_Item_Id__c, Opportunity.QBO_Invoice_Id__c.
Ordering matters — an invoice needs its customer and items to exist in QuickBooks first:
- Sync Customers (Accounts)
- Sync Items (Products)
- Sync Invoices (Opportunities)
Add a Record Filter to each outbound profile to limit which records sync (e.g. only Opportunities in a certain stage). Without a filter, every record of that object is a candidate.
9Activate and run your first sync
- Console → Sync Profiles → activate Account → QuickBooks Customer (toggle Activate).
- Click Run now. Watch the Logs tab — you should see records created with a QuickBooks Id written back.
- Repeat for Item, then Invoice, in that order.
Start with a Record Filter that matches only a handful of records for the very first run, confirm they look right in QuickBooks, then widen it.
Names with a colon (e.g. SLA: Gold): QuickBooks treats : as a sub-item separator. The connector's Replace Colon transformation handles this on the shipped templates — leave it in place.
10Turn on automatic payment reconciliation
So paid invoices update in Salesforce without anyone clicking:
- Console → Sync Profiles → QuickBooks Invoice → Opportunity (Payment Reconciliation).
- Set Trigger Type = Scheduled, Interval = Hourly (or as you prefer). Activate.
- Confirm the background jobs are running: the console Diagnostics tab shows "Sync dispatcher scheduled." If it says the dispatcher isn't scheduled, an admin registers them once:
Setup → Developer Console → Debug → Open Execute Anonymous Window
integos.IOS_InstallHandler.scheduleAll();
This one-time step schedules the dispatcher, health monitor, and log-retention jobs. Re-running it is safe — it never duplicates jobs.
Once running, each Opportunity's QBO Payment Status (Paid / Partially Paid / Open) and QBO Balance update automatically from QuickBooks.
11The "Generate QuickBooks Invoice" button
For on-demand invoicing from a single Opportunity:
- Add the Generate QuickBooks Invoice action to your Opportunity page layout (Setup → Object Manager → Opportunity → Page Layouts → Mobile & Lightning Actions).
- On any Opportunity, click it. The connector checks it isn't already invoiced, then sends it. The QBO Invoice No. field populates within moments.
§Validation rules & the integration user
When data flows into Salesforce (for example, payment reconciliation), the connector performs standard DML — so your org's validation rules, required fields, Apex triggers, flows, and duplicate rules all run. They are never bypassed by default. A record that fails a rule fails on its own, with the exact rule message written to the sync log; every other record in the batch still syncs.
If a specific rule shouldn't apply to synced writes, exempt it deliberately using the shipped opt-in permission:
- Pick the integration user that runs your syncs. Scheduled syncs run as the user who scheduled them — so run
integos.IOS_InstallHandler.scheduleAll();and activate profiles as that user (a dedicated integration user is cleanest). - Assign that user the
Integration OS - Bypass Validationpermission set — in addition to Integration OS Admin and QuickBooks Integration. It is a separate set on purpose, so nobody bypasses rules by accident. - Edit only the validation rules you want the sync to skip and add the permission check to the rule formula:
AND(
NOT($Permission.integos__IOS_Bypass_Validation),
/* ...your existing rule logic... */
)
Now that integration user's syncs skip exactly those rules, while every other user — and every rule you didn't touch — stays fully validated.
Keep it scoped: assign Integration OS - Bypass Validation only to the integration/running user. Don't add the permission to the general Admin/User sets, or human admins would also skip those rules while editing records in the UI.
◎Monitoring — the Admin Console
App Launcher → Integration OS Admin Console:
- Overview — success rate, records synced, failures, connection health at a glance
- Diagnostics — active checks for silent problems: unscheduled jobs, duplicate profiles, missing filters, unhealthy connections. Check this first if something seems off.
- Connections / Sync Profiles / Logs — full detail; filter logs to Failed to triage
⚙Troubleshooting
| Symptom | Cause & fix |
|---|---|
| Connection Unsupported | Not a US / USD company. This version is USD-only. |
| Sync fails, authorization error, though connection is Authenticated | The External Credential Principal grant is missing on the user's permission set (Step 3e). |
| Scheduled profile never runs | The background dispatcher isn't registered (Diagnostics flags it). Run integos.IOS_InstallHandler.scheduleAll(); once in Execute Anonymous. Safe to re-run. |
| Duplicate customers / records in QuickBooks | Two active profiles syncing the same object. Diagnostics flags "Duplicate outbound profiles." Deactivate all but one. |
| Item sync fails, "Select a category" / income account error | The IncomeAccountRef isn't set (Step 7), or the product name contains a : (keep the Replace Colon transformation). |
| Invoice update fails, "Stale Object" | The invoice was edited directly in QuickBooks. The connector auto-recovers on the next run; no action needed. |
| Everything logs but nothing appears in QuickBooks | Check the profile is Active and the connection is Healthy (not Unsupported). |
| Inbound sync fails on a validation rule or required field | The record didn't satisfy one of your org's validation rules or a required field — these always run on inbound writes. Either map the missing field, or let the sync skip that specific rule: assign the sync-running user the Integration OS: Bypass Validation Rules permission set and add NOT($Permission.integos__IOS_Bypass_Validation) to the rule's formula. Failures are logged per-record and never block the rest of the batch. |
| Logs growing large | The nightly retention job purges old logs; adjust the retention window in Integration OS Settings. |
▲Going live (from sandbox to production)
- Swap the Auth Provider keys to your Production Intuit keys.
- Change the Named Credential URL to
https://quickbooks.api.intuit.com. - Add the production Redirect URI to your Intuit app; re-authenticate (Step 3d) against your real company.
- Update the connection's Company / Realm Id to your production company.
- Re-run Test connection — expect Healthy.
- Do a small, filtered first sync in production before widening.
?Support
- Diagnostics tab first — it catches most setup issues automatically.
- Logs tab, filtered to Failed, shows the exact QuickBooks error per record.
- Still stuck? Email support@sfbro.com with your org Id, the profile name, and the failed log entry.
- Keep your Intuit Client Secret private; rotate it from the Intuit dashboard if exposed.