qbo source reads 63 QuickBooks Online accounting resources through the
v3 REST API using an HTTP manifest.
The connector is alpha and supports sandbox and production accounts.
The qbo alias resolves to qbo@v3. Live company reads have not been validated.
Configuration
Get credentials with the OAuth Playground
Use your own Intuit application. The Developer Portal provides the app’s client ID and client secret. The OAuth Playground helps you authorize a company and exchange the authorization code for tokens. Filament does not host the initial authorization callback.- Sign in to the Intuit Developer Portal and create or select an app with access to the QuickBooks Online Accounting API.
- Open the app’s Keys & OAuth or Keys & Credentials section. Copy the client ID and client secret for your environment. Use development credentials for a sandbox company and production credentials for a live company. Complete Intuit’s production setup requirements before connecting a live company.
-
Check the app’s redirect URI settings for the selected environment. The
Playground redirect URI may already be registered by default. Add it only
if it is missing.
-
Open the OAuth 2.0 Playground.
Select your app and environment or enter the matching app credentials. Use
the registered redirect URI and select the
com.intuit.quickbooks.accountingscope. -
Start authorization, sign in to QuickBooks, select the company, and approve
access. After the redirect, copy the
realmId. This is the company ID that Filament callsrealm_id. - Complete the Playground’s code exchange step to obtain an access token and a refresh token. The authorization code is temporary and single-use. It is not an access token or refresh token and cannot be entered in either field.
-
Create a saved
qboconnection in Filament using the values below.
Leave
access_token empty when using automatic refresh. Filament obtains an
access token on the first read and saves replacement tokens for subsequent runs.
Store the client secret and refresh token as managed secrets on the saved
connection. Once Filament manages the refresh token, avoid refreshing the same
token in the Playground or another application.
If you perform the code exchange yourself, send a form-encoded POST to
https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer. Use HTTP Basic
authentication with the client ID and client secret. Include
grant_type=authorization_code, code, and the exact redirect_uri used for
authorization. Save the returned refresh token, not the authorization code.
The realmId comes from the authorization redirect rather than this exchange.
See Intuit’s app credential guide
and OAuth Playground guide.
Access-token-only connections remain supported and require manual renewal.
Their connection test reads CompanyInfo.
Automatic token refresh
The HTTP engine uses Filament’s sharedoauth package. Automatic refresh requires
a saved connection with a managed refresh_token secret in PostgreSQL, SQLite,
AWS Secrets Manager, or Google Secret Manager. Tokens remain in the configured
manager. Environment-only and inline credentials are not supported for automatic
refresh through the runner. Go callers can
instead bind an oauth.Store with Source.SetOAuthStore.
The first read exchanges the saved refresh token. The optional access_token
field is ignored when refresh credentials are configured. Later reads reuse
the run’s access token until its expiry is within 30 seconds. If QuickBooks
rejects it with HTTP 401, the source refreshes and replays the read once. A
second 401 stops the read. Concurrent callers within the run reuse the fresh replacement.
Access tokens and expiry stay in memory for one run. Only a changed refresh
token is saved to the existing refresh_token secret. Rotation does not create
a secret or change the connection row. PostgreSQL and SQLite update the encrypted
value in place. AWS adds a version under the same name. GCP adds a version and
destroys the previous one.
Each run loads the saved refresh token once. Calls within the run share token
state, while separate runs refresh independently. There are no datastore locks
around token exchanges and no coordination table. Token requests have a
30-second timeout and honor cancellation.
Configuration validation for automatic-refresh connections is local only.
The validation RPC does not exchange tokens. The first move verifies live
access. Local catalog discovery remains available without exchanging tokens.
A revoked or expired refresh token requires reauthorization. Failed or ambiguous
token exchanges are not automatically retried. Save failures stop the read.
The run retains a successful exchange for a later save attempt while it remains
alive. A process exit between upstream rotation and persistence can still
require reauthorization.
Tokens and upstream OAuth error descriptions are never emitted in activity or
logs. See Intuit’s refresh-token guidance.
Resources
The ten core resources are enabled by default. All other resources are optional. Account features,
region, and permissions determine which resources can be read. Discovery
returns a local catalog and does not probe those entitlements. An unavailable
selected resource fails the read instead of being silently omitted.
Employees are accounting Employee records. Time activities are accounting
TimeActivity entries. These do not include Workforce payroll or QuickBooks Time
timesheets. Attachments include metadata, notes, and linked entity references.
File content is not downloaded. Budgets retain their nested budget details.
Recurring transactions retain the transaction wrapper, schedule, lines, and
references. They are templates rather than the transactions generated from them.
Company currencies list configured currencies. Exchange rates read only the
configured source currencies on one explicit date, against the company home
currency. Currency reads require multicurrency support. There is no automatic
rate-history backfill.
Selecting
exchange_rates requires both exchange-rate pipeline fields, including
when selecting every resource. Set both fields or deselect that resource. Missing
fields fail resource planning before destination setup and resource start events.
Reports
Each report produces one snapshot row. Header fields have typed columns such asheader_report_name, header_time, and header_currency. The columns and
rows JSON columns preserve the dynamic column definitions, nested sections,
and subtotals. Empty reports are preserved. The connector does not assign
identities to report line positions.
Period reports use
report_start_date and report_end_date. Aging reports and
customer or vendor balance reports use report_date instead. The account list
does not use date filters. Omitted dates use the upstream report defaults, not
all history. The returned header records the effective period and basis.
Accounting basis and other report-specific filters use Intuit’s defaults.
Report reads call /reports/{name} once per selected report. They do not use
entity query pagination. An extraction row limit limits snapshots, not the
number of lines within a report. Use a smaller date range for large reports.
The HTTP engine rejects responses larger than 100 MiB. There is no automatic report
partitioning or reconstruction of data omitted by the upstream report service.
The catalog follows Intuit’s 29 supported report families.
Display names can differ from endpoint names. Sales reports use ClassSales,
CustomerSales, DepartmentSales, and ItemSales. The account list uses
AccountList. Retired and undocumented reports are not added as extra resources.
Coverage boundaries
The new resources remain alpha. Fixture tests verify request construction and
response handling. No live company reads have been validated. Company currency
queries in particular still need live confirmation of query pagination and
inactive-currency visibility. Optional resource failures remain visible.
Modes
All resources support full replacement, upsert, and append. The 14 transaction resources also support incremental upsert and append. Use upsert to reconcile replayed records. The first incremental run reads all currently available records. Later runs filter onMetaData.LastUpdatedTime, exposed as updated_at. The lower bound
is inclusive and stays fixed throughout pagination. The default lookback is
five minutes. Boundaries are rounded down to whole seconds so timestamp
precision does not skip records. Transaction dates and SyncToken are not
incremental cursors.
Only a completed resource sends a new watermark through Filament’s normal
destination acknowledgement path. Interrupted or limited
reads retain the previous watermark and replay. Empty results also retain the
previous watermark. Full reads restart from the beginning after interruption.
Query reads do not capture deleted transactions. Full replacement reconciles
records that no longer exist. Upserts alone retain deleted destination rows.
Paginated entity queries use ORDERBY Id ASC before STARTPOSITION and
MAXRESULTS. Explicit ordering avoids relying on an unspecified response order.
Sorting by the immutable ID keeps edits to names and timestamps from changing
a record’s sort position. See Intuit’s query guidance.
Ordering does not provide snapshot isolation. Inserts, deletions, and changes
to which records match the filter can still shift offsets between requests,
causing skipped or repeated records. The five-minute lookback cannot guarantee
recovery from every such change or an arbitrary indexing delay. Use periodic
full replacement when a current view is required. The source does not advertise CDC.
Behavior
For entity resources, one row represents one entity. The primary key isrealm_id and id. Company
information and preferences each produce one row keyed by the company ID.
Each resource has typed columns based on Intuit’s accounting response schemas.
Each resource declares its destination mapping in a separate manifest file.
Missing and regional fields are nullable.
Postgres receives numeric, date, boolean, and JSONB columns. Snowflake receives
NUMBER, DATE, BOOLEAN, and VARIANT columns through the shared destination type
mapping. Amounts never pass through floating point. Values outside the declared
decimal precision or scale fail the read instead of being rounded.
The trailing
raw JSON column preserves unprojected fields and unknown nested
attributes. JSON columns retain their original numeric precision. Lines remain
nested and are not expanded into separate resources. Preferences expose typed
setting fields. Recurring templates expose their transaction type, common
transaction fields, and schedule, with variant-specific fields retained in raw.
Company currencies use their currency code as id. Exchange rates encode the
source currency and effective date into id. Recurring templates encode the
transaction type and nested entity ID. Reports encode the endpoint, returned
period, accounting basis, currency, and request parameters. These composite
identities use JSON arrays to avoid delimiter collisions. Report generation
time is not part of the key, so upsert replaces the same report snapshot.
Use append to retain repeated snapshots or full replacement to retain only the
latest extraction. Reports leave entity timestamps and activity flags null.
Entity reads use GET /v3/company/{realm_id}/query. SQL-like queries page with
one-based STARTPOSITION and MAXRESULTS. The original reference resources and
employees explicitly include active and inactive records. Other optional query
resources use upstream visibility defaults. Company settings use their singleton endpoints.
An empty query response ends the read. Fault envelopes and malformed responses
fail visibly. Repeated record IDs across pages fail the resource to avoid
advancing its watermark on an inconsistent scan.
Resources may read concurrently through a shared limiter of five requests per
second per source instance. Other runs share the upstream company quota, so this local limiter
does not reserve quota across workers. Server errors receive up to three retries. Throttled requests retry within a
ten-attempt request budget. Retry-After is honored when present. A throttled
response without that header waits 60 seconds. Cancellation interrupts retry waits.
See Intuit’s accounting API collection,
query builder,
Payment query reference,
and API limits.