QuickBooks
Sync customer, vendor, and invoice data from your warehouse to QuickBooks Online. Keep your accounting records enriched with the latest profile data, billing addresses, and contact information from your data warehouse.
Prerequisites
- A QuickBooks Online account (any plan)
- An Intuit developer app with OAuth 2.0 credentials (Client ID and Client Secret)
- The
com.intuit.quickbooks.accountingscope enabled on your Intuit developer app - Your QuickBooks Company ID (Realm ID)
Permissions
Your Intuit developer app must have the Accounting scope (com.intuit.quickbooks.accounting) enabled. This grants read and write access to customers, vendors, invoices, and other accounting entities.
To create an app:
- Go to the Intuit Developer Portal
- Navigate to My Apps and click Create an app
- Select QuickBooks Online and Payments
- Enable the Accounting scope
- Note down the Client ID and Client Secret from the app’s Keys & credentials section
Authentication
QuickBooks uses OAuth 2.0 for authentication. Zeotap supports two methods:
OAuth 2.0 (Recommended)
- In Zeotap, click Connect on the QuickBooks destination
- You will be redirected to Intuit’s authorization page
- Log in to your QuickBooks account and authorize access
- Select the QuickBooks company you want to connect
- You will be redirected back to Zeotap with the connection established
Zeotap automatically refreshes access tokens before they expire (tokens are valid for 1 hour, refresh tokens for 100 days).
Access Token (Manual)
If you prefer to manage tokens yourself (e.g., for development or testing):
- Go to the Intuit OAuth 2.0 Playground
- Select your app and authorize it against your QuickBooks company
- Copy the Access Token and Refresh Token
- In Zeotap, select Access Token as the authentication method
- Paste the access token, refresh token, client ID, and client secret into the corresponding fields
Important: Access tokens expire after 1 hour. If you provide a refresh token along with your client ID and client secret, Zeotap will automatically refresh the access token. Without a refresh token, the connection will stop working after the token expires.
Configuration
| Field | Type | Required | Description |
|---|---|---|---|
| Company ID (Realm ID) | Text | Yes | Your QuickBooks company ID. Found in Settings > Account and Settings or in the URL when logged into QuickBooks Online (the numeric value after /app/). |
| Environment | Select | Yes | Production for live QuickBooks data, Sandbox for testing with the Intuit sandbox environment. |
Target Settings
| Field | Type | Required | Description |
|---|---|---|---|
| QuickBooks Object | Select | Yes | The QuickBooks entity to sync to: Customers, Vendors, or Invoices. |
| ID Field | Text | No | The mapped field that contains the QuickBooks object ID for update and upsert operations. Leave blank to always create new records. |
Supported Operations
Sync Modes
| Mode | Supported |
|---|---|
| Upsert | Yes |
| Insert | Yes |
| Update | Yes |
| Mirror | — |
Audience Sync Modes
| Mode | Supported |
|---|---|
| Add | — |
| Remove | — |
| Mirror | — |
| Upsert | — |
QuickBooks does not have a list or audience membership concept, so audience sync modes are not supported.
Features
- Field Mapping: Yes
- Schema Introspection: No — QuickBooks fields are well-known and provided as default destination fields
Required Mapping Fields
| Object | Required Fields |
|---|---|
| Customers | DisplayName — Full display name for the customer |
| Vendors | DisplayName — Full display name for the vendor |
| Invoices | CustomerRef — QuickBooks customer ID that the invoice belongs to |
Default Destination Fields
Customer Fields
| Field | Type | Description |
|---|---|---|
SyncToken | string | QuickBooks SyncToken (version number) — required for update and upsert-by-id operations |
DisplayName | string | Full display name (required, must be unique across all customers) |
GivenName | string | Customer’s first name |
FamilyName | string | Customer’s last name |
CompanyName | string | Customer’s company name |
PrimaryEmailAddr | string | Primary email address |
PrimaryPhone | string | Primary phone number |
BillAddr_Line1 | string | Billing address line 1 |
BillAddr_City | string | Billing address city |
BillAddr_CountrySubDivisionCode | string | Billing address state or province |
BillAddr_PostalCode | string | Billing address postal code |
BillAddr_Country | string | Billing address country |
Vendor Fields
| Field | Type | Description |
|---|---|---|
SyncToken | string | QuickBooks SyncToken (version number) — required for update and upsert-by-id operations |
DisplayName | string | Full display name (required, must be unique across all vendors) |
GivenName | string | Vendor’s first name |
FamilyName | string | Vendor’s last name |
CompanyName | string | Vendor’s company name |
PrimaryEmailAddr | string | Primary email address |
PrimaryPhone | string | Primary phone number |
Invoice Fields
| Field | Type | Description |
|---|---|---|
SyncToken | string | QuickBooks SyncToken (version number) — required for update and upsert-by-id operations |
CustomerRef | string | QuickBooks customer ID the invoice is for (required) |
Line_Amount | number | Invoice line item amount |
Line_Description | string | Invoice line item description |
DueDate | string | Invoice due date (YYYY-MM-DD format) |
DocNumber | string | Invoice document number |
How It Works
-
Field Mapping: Zeotap maps your warehouse columns to QuickBooks entity fields. Standard fields are sent as top-level JSON properties. Nested fields (email, phone, addresses) are automatically structured into the format QuickBooks expects.
-
Batch API: QuickBooks Online supports a batch API that processes up to 30 operations in a single HTTP request. Zeotap automatically chunks your data into batches of 30 and sends them sequentially. Each item in a batch is processed independently — a failure in one item does not affect others.
-
Request Format: QuickBooks uses JSON request bodies with Bearer token authentication. Each batch request is sent as a
POSTto/v3/company/{realmId}/batchwith aBatchItemRequestarray. -
Sync Mode Behavior:
- Insert: Creates a new entity for every row. The batch operation is set to
create. - Update: Updates an existing entity by ID. Requires a QuickBooks object ID in the configured ID field and a
SyncTokencolumn for optimistic concurrency. Usessparse: trueto only update the fields you map (leaving other fields untouched). - Upsert: If a QuickBooks object ID is present, sends an update (SyncToken required). If no ID is present, sends a create. Both are included in the same batch when applicable.
SyncToken requirement: QuickBooks requires a
SyncTokenon every update request for optimistic concurrency. Map a column namedSyncTokenfrom your warehouse (obtained via a prior read from the QuickBooks API). If the SyncToken is missing or stale, the update is rejected by the API with a “Stale Object” fault and the row is reported as failed. - Insert: Creates a new entity for every row. The batch operation is set to
-
Error Handling: Each item in the batch response is checked individually. Failed items include error codes and messages from QuickBooks. Transient errors (rate limits, server errors) are retried automatically with exponential backoff.
-
Token Refresh: When using OAuth 2.0 or providing a refresh token, Zeotap automatically refreshes the access token before it expires. Access tokens are valid for 1 hour; refresh tokens are valid for 100 days (rolling — the expiry extends each time the token is used).
Rate Limits
QuickBooks Online enforces several rate limits:
| Limit | Value |
|---|---|
| Requests per minute per company | 500 |
| Batch requests per minute per company | 40 |
| Items per batch request | 30 |
| Requests per second per app | 10 |
Zeotap automatically handles rate limiting:
- HTTP 429 responses trigger exponential backoff with retry
- Up to 3 retries per batch request
- Batches are sent sequentially (not concurrently) to stay within limits
At 30 items per batch and 40 batches per minute, the effective throughput is approximately 1,200 records per minute per company.
Best Practices
- Use sandbox first: Set the environment to Sandbox and test your sync with the Intuit sandbox before pointing at production data.
- Map the ID field for upsert/update: Configure the ID Field in target settings and map a column containing the QuickBooks object ID. Without it, upsert mode creates duplicate records.
- Map a SyncToken column for updates: QuickBooks requires the current SyncToken on every update. Include a
SyncTokencolumn in your warehouse model (read from QuickBooks on a schedule and join onto your outbound data) so updates succeed. Updates without a SyncToken only work for records that have never been modified. - Use sparse updates: Update mode uses
sparse: trueby default, so only the fields you map are overwritten. Unmapped fields on the QuickBooks entity remain untouched. - DisplayName must be unique: QuickBooks requires unique
DisplayNamevalues for customers and vendors. Duplicate names will cause API errors. - Address fields use prefixes: Map address components using the
BillAddr_orShipAddr_prefix (e.g.,BillAddr_Line1,BillAddr_City) to populate structured address objects on the entity. - Invoice line items: Each row creates an invoice with a single line item. For multi-line invoices, create the invoice first and then add lines via a separate sync or the QuickBooks UI.
Troubleshooting
Authentication failed: access token is invalid or expired
Re-authenticate via OAuth or provide a fresh access token. If using the manual access token method, ensure you also provide a refresh token, client ID, and client secret so Zeotap can refresh the token automatically.
Company ID (Realm ID) not found
Verify the Realm ID is correct. You can find it in the URL when logged into QuickBooks Online (e.g., https://app.qbo.intuit.com/app/homepage?company_id=1234567890 — the company_id parameter is your Realm ID). Also check that the environment setting (production vs sandbox) matches your QuickBooks account.
DisplayName must be unique
QuickBooks requires unique DisplayName values for customers and vendors. If you see a “Duplicate Name Exists” error, check your data for duplicate display names or append a unique suffix (e.g., email address) to ensure uniqueness.
Object ID is required for update mode
Update mode requires a QuickBooks object ID for each row. Ensure the ID Field is configured in target settings and that the corresponding column in your warehouse contains valid QuickBooks IDs (numeric strings).
Rate limiting (429 errors)
QuickBooks limits API requests to 500 per minute per company and 40 batch requests per minute. Zeotap retries automatically, but persistent rate limit errors may indicate too many concurrent syncs against the same company. Reduce sync frequency or stagger syncs across time windows.
Invoice missing CustomerRef
Invoices require a CustomerRef field containing the QuickBooks customer ID. Ensure this field is mapped and contains valid customer IDs from your QuickBooks company. You can find customer IDs by querying the QuickBooks customer list or from a previous customer sync.
SyncToken mismatch on update
QuickBooks uses optimistic concurrency via SyncToken. Every update request must include the record’s current SyncToken. Map a SyncToken column from your warehouse (populated from a prior QuickBooks read) so Zeotap can send it with each update. If another process updates the same record between your read and write, the update fails with a “Stale Object” error — re-read the record from QuickBooks to refresh the SyncToken and retry. Reducing sync frequency or running QuickBooks reads immediately before writes also minimises conflicts.
Sandbox vs production data mismatch
Sandbox and production are completely separate environments with different data, different Realm IDs, and different API base URLs. Customer IDs from sandbox do not exist in production. When switching environments, update your Realm ID and expect new records to be created.