Integrating QuickBooks Online with a Procurement Platform
A practical guide to syncing purchase orders, vendors and bills between a procurement platform and QuickBooks Online — OAuth setup, the data model that actually matters, and the sync patterns that survive contact with real customers.
For most SMB customers QuickBooks Online (QBO) is the system of record for AP. If your procurement platform cannot push approved bills into QBO cleanly, you are asking finance to do double entry — and they will quietly stop using you. This guide covers what an integration actually has to do.
The data model in two minutes
QBO exposes a REST API over a coherent accounting model. For procurement, four entities matter most:
- Vendor — the supplier you are buying from. Holds tax IDs, payment terms, default expense account, currency, 1099 flags.
- Account — the chart of accounts. Bills must post to an Expense or Other Current Asset account; payments draw from a Bank or Credit Card account.
- PurchaseOrder — non-posting document representing an open commitment. Lines reference either Items or Accounts.
- Bill — the posting AP transaction. Once a bill exists, QBO recognises the liability and the expense.
Two more are worth mentioning: Item (used when customers track inventory in QBO rather than in your platform) and Class/Department (used for cost-centre allocation in QBO Plus and Advanced).
OAuth 2.0 setup
QBO uses OAuth 2.0 with the Authorization Code flow. The high-level steps:
- Register an app at developer.intuit.com and capture the client ID and secret.
- Redirect the user to Intuit's
/connect/oauth2 endpoint with scope com.intuit.quickbooks.accounting.
- Exchange the returned authorization code at the token endpoint for an access token (1 hour) and refresh token (101 days, rolling).
- Persist the
realmId Intuit returns — it identifies the QBO company and must accompany every API call.
- Refresh the access token proactively; refresh tokens rotate, so always store the latest one.
Sandboxes are available per developer account and behave identically to production except for billing — use them for CI.
Sync patterns that actually work
Three patterns dominate. Pick deliberately.
1. Push on approval
When a bill is approved in your platform, create the corresponding QBO Bill via the API in the same transaction. Store the QBO Id and SyncToken on your record. This is the simplest model and the right default.
2. Change Data Capture (CDC) for pulls
QBO's /cdc endpoint returns all entities of the requested types changed since a timestamp. Use it to detect vendor edits, account additions and bill status changes made directly in QBO. Run it on a short interval (every 5–15 minutes) and update your local mirror.
3. Webhooks for invalidation
Webhooks fire when entities change. They are not delivery-guaranteed and do not contain the payload — treat them as cache-invalidation signals that trigger a targeted read, not as the source of truth.
Anti-pattern: doing a full SELECT * FROM Bill every night. You will hit QBO's 500 requests/minute limit on any non-trivial customer and your customers will see stale data all day. CDC plus webhooks is the right shape.
Mapping the procurement model to QBO
The mapping is rarely 1:1. Some real-world decisions you will have to make:
- POs: Push as QBO PurchaseOrders, or keep them in your platform and only sync the resulting Bill? Pushing POs gives finance visibility but doubles the surface area for sync errors.
- GL coding: Let users pick the QBO Expense Account at the PO line level, and cache the chart of accounts locally so the picker is fast.
- Multi-entity: Each QBO company is a separate
realmId. If your customer has five entities, you have five OAuth connections.
- Multi-currency: Only QBO Essentials and above support it; check the company info
MultiCurrencyEnabled flag before sending foreign-currency bills.
- Attachments: The Attachable endpoint accepts the original supplier PDF — always attach it so auditors can find the source document inside QBO.
Failure modes to design for
- Stale SyncToken — QBO uses optimistic concurrency; if someone edits the bill in QBO between your read and write, you get an error. Always refetch and retry once.
- Token expiry on long jobs — refresh the access token before each batch, not just at job start.
- Disconnected companies — users can revoke access from inside QBO at any time. Catch
AuthenticationFailed, mark the connection as broken, and prompt the user to reconnect.
Sources and further reading: Intuit Developer — QuickBooks Online Accounting API, Intuit Developer — OAuth 2.0 guide.