QuickBooks Online
Connect QuickBooks Online accounting data to Nexus over the v3 REST API with read, write, and schema discovery. Filter and order-by push down into the QBO query language; aggregation runs in the Nexus engine.
The QuickBooks Online connector (bundle version 2.0.1) gives Nexus read, write, and discovery access to your QBO company over the Intuit Accounting API v3. Finance and operations teams can query accounting entities, automate record creation, and integrate QBO into cross-system pipelines without exporting CSVs or embedding credentials in code.
This page is for engineers wiring QBO into Nexus. It covers OAuth token handling, the exact pushdown boundary (filter and order push down; aggregation does not), the supported entities and operators, write semantics including the entities QBO will not let you hard-delete, and the failure modes you should design around.
The pushdown boundary, up front
QBO's query language supports WHERE and ORDERBY but has no GROUP BY, JOIN, or aggregate surface. The adapter therefore declares filter and order pushdown only:
- Your
WHEREconditions and ordering are rendered into the QBO query string and evaluated by Intuit. - Any operator QBO cannot express is re-applied in the Nexus engine as a safety net (the clean fallback described in Operators & pushdown), so results are never silently wrong.
- Aggregation and
GROUP BYalways run in the Nexus engine, after rows are fetched, bounded by the engine's post-process row budget. Filter down to the smallest useful set before aggregating.
Do not assume the uniform SQL pushdown you get from the database connectors — QBO is a filter-and-order surface with in-engine aggregation.
Authentication
QuickBooks Online uses OAuth 2.0 with a rotating refresh token. There is no API key option. You authorize a QBO company once through the Intuit OAuth flow, which produces a refresh token. From then on, Nexus:
- Mints short-lived access tokens (1-hour TTL) automatically.
- Persists each new refresh token back to Key Vault after every rotation, so the connection survives restarts and replica changes without manual re-seeding.
- Serializes concurrent refresh calls so two replicas cannot double-rotate and orphan each other's token.
Required secrets
| Secret name | Description |
|---|---|
quickbooks.client_id |
Client ID from your Intuit developer app |
quickbooks.client_secret |
Client Secret from your Intuit developer app |
quickbooks.refresh_token |
Seed refresh token from the OAuth consent flow |
quickbooks.realm_id |
Company ID (realmId) of the QBO company |
quickbooks.__opt_environment |
production (default) or sandbox |
quickbooks.__opt_minor_version |
API minor version; defaults to 75 |
One bridge = one company. To connect multiple QBO companies, create one bridge per company. All secrets live in your tenant Key Vault; see Secrets.
Connecting a QuickBooks company
What you need
- An Intuit developer app with the Accounting scope (
com.intuit.quickbooks.accounting). Create one at developer.intuit.com if your organization does not already have one. - Admin access to the QuickBooks company you want to connect.
- A decision on Production vs Sandbox — the setup steps are identical for both.
Step 1: Get a refresh token and realm ID
The fastest path is the Intuit OAuth 2.0 Playground:
- Select your app from the dropdown.
- Tick the
com.intuit.quickbooks.accountingscope and choose your environment. - Click Get authorization code and authorize the target company.
- Click Get tokens. Copy the Refresh Token and the Realm ID shown on the page.
Do this immediately before the next step. The refresh token rotates the moment anything exchanges it (including clicking "Refresh token" again in the Playground), so do not generate it and leave it idle.
Step 2: Create a QuickBooks bridge in Nexus
In the Nexus admin console or management API, create a new QuickBooks bridge and supply the six secrets above. Set quickbooks.__opt_environment to sandbox if you authorized a sandbox company. Nexus stores these in Key Vault and manages all subsequent token rotation automatically.
Step 3: Verify the connection
Run a discovery or a simple query (for example, list a few customers) to confirm the connection is live. A successful result means Nexus has obtained a working access token from your stored refresh token.
Supported entities
The connector exposes all standard QuickBooks Online entities for reading, including Account, Bill, BillPayment, Customer, Deposit, Employee, Estimate, Invoice, Item, JournalEntry, Payment, Purchase, PurchaseOrder, SalesReceipt, Vendor, and more. Schema discovery lists the full set available in your company.
Capabilities
| Capability | Supported |
|---|---|
| Read | Yes |
| Write (create, update, delete) | Yes |
| Merge (upsert) | No — insert/update/delete only |
| Schema discovery | Yes |
WHERE filter pushdown |
Yes — rendered into the QBO query language |
| Order-by pushdown | Yes — rendered as ORDERBY |
Aggregation / GROUP BY pushdown |
No — aggregate in the Nexus engine |
Supported filter operators
$eq, $ne, $gt, $gte, $lt, $lte, $like, $in, $not_in, $between, $empty, $contains, $starts_with, $ends_with, $expr
QBO's query language natively supports =, IN, <, >, <=, >=, and LIKE. Operators that map to constructs QBO does not accept (such as $ne) are either evaluated in-engine or rejected at the API level — keep filters within the natively supported set for server-side evaluation.
Example: read open invoices
The adapter translates a UQL read into the QBO query string format. For open invoices ordered by date, it emits:
SELECT * FROM Invoice WHERE Balance > 0 ORDERBY TxnDate DESC STARTPOSITION 1 MAXRESULTS 100
QBO uses ORDERBY as a single word (not ORDER BY) and STARTPOSITION/MAXRESULTS for pagination. The adapter emits these forms automatically; you do not write them yourself.
Writing records
| Operation | Behavior |
|---|---|
| Create | POST a full QBO object. Supply all fields the entity type requires. |
| Update | Sparse update: provide the record ID and only the fields to change. The adapter fetches SyncToken automatically. |
| Delete | Supported for transaction entities (invoices, bills, payments). SyncToken is auto-fetched. |
| Merge (upsert) | Not supported. Read the record first, then branch to create or update. |
Name-list entities cannot be hard-deleted
QuickBooks Online does not allow permanent deletion of Customers, Items, Accounts, or Vendors. To deactivate one, use a sparse update with Active = false:
await ctx.adapters.quickbooks.update(
collection="Customer",
record_id="42",
set={"Active": False},
)
CompanyInfo and Preferences are read-only collections; write attempts against them are rejected by the adapter's writability gate before any request is sent, independent of the caller's RBAC grants.
Limits & behavior notes
- Aggregation is in-engine. Any
GROUP BY/SUM/COUNTruns in Nexus after fetch — bound the fetched set with a tightWHEREandlimit. - No upsert. There is no atomic merge; emulate it with a read-then-write branch.
- Refresh-token drift is the main failure mode. A refresh token unused for ~100 days, or copied and then rotated out from under Nexus, becomes invalid — re-seed via Step 1.
- Pagination is
STARTPOSITION/MAXRESULTS. Large result sets page automatically; very large scans are still subject to Intuit's API throttling. - HTTP 429 backoff. The adapter backs off on Intuit 429 responses; this is adapter-level HTTP backoff, not pipeline-run retry (Nexus does not auto-retry a failed run).
Troubleshooting
| Symptom | Fix |
|---|---|
invalid_grant: incorrect or invalid refresh token |
The token rotated after you copied it, or was unused for over 100 days. Redo Step 1 and update quickbooks.refresh_token. |
| Redirect URI mismatch during authorization | Add the URI shown by the Playground to your app's Redirect URIs, save, and retry. |
| Queries return no rows, no error | Confirm quickbooks.realm_id and quickbooks.__opt_environment match the company you authorized. |
400 on a query |
QBO rejected the syntax. Its query language supports WHERE, ORDERBY, and comparisons but not GROUP BY, JOIN, or !=. |
| Fails after a long idle period | Re-seed quickbooks.refresh_token via Step 1 — a restart during an idle rotation window can leave the persisted token out of sync. |
See also
- Connectors overview — the shared adapter contract and capability matrix
- Operators & pushdown reference — how filter/aggregation pushdown is decided
- Secrets · Connections & bridges
- Built-in workspace — stage QBO reads for cross-system joins
- Pipeline SDK