QuickBooks – Gotchas
QuickBooks is an accounting software package developed and marketed by Intuit. QuickBooks products are geared mainly toward small and medium-sized businesses and offer on-premises accounting applications as well as cloud-based versions that accept business payments, manage and pay bills, and payroll functions.
53 gotchas across 23 resources
These are connector-specific behaviors and limitations to be aware of when integrating.
Attachments2 gotchas
attachmentsAllQuickBooks Online does not expose a reliable cross-page total record count. meta.total_count will not appear. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
attachmentsUploadQuickbooks limits attachment uploads to 100MB.
Balance Sheet1 gotcha
balanceSheetOneWhen using start and end date filters, QuickBooks requires both to be sent. However, the report only reflects the balance sheet situation as of the end date.
Bill Payments2 gotchas
billPaymentsAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
billPaymentsAddPayment method is required and must be Check or CreditCard.
Bills4 gotchas
billsAllOn bill line items, QuickBooks returns ClassRef.name as the FullyQualifiedName
(e.g. "Fruit:Apple") rather than the leaf class name. Apideck normalises this by
extracting the last : segment, so tracking_categories[].name returns "Apple" and
parent_name returns "Fruit". Expense line items are unaffected — QuickBooks returns
only the short name there.
billsAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
billsAddWhen creating a bill in QuickBooks, each line item must be accompanied by a type designation. If the type is set to "expense_item," an item ID is required. Conversely, if the type is "expense_account," a ledger account ID must be provided.
reference and notes both map to the single PrivateNote field — QuickBooks' one reference-number slot (DocNumber) is taken by bill_number on bills, so reference shares the memo instead. Only one of the two survives a write (the other is dropped with no error), and on read both are populated from PrivateNote and are always identical. Send only one. Which of the two wins on write is currently under review — do not rely on it.
bill_number maps to DocNumber, limited to 21 characters; a longer value is rejected with 400 ValidationFault (code 6000), so a 36-character UUID does not fit.
Additionally, multicurrency needs to be enabled in your QBO account. If creating a bill in your default currency, you do not need to send the currency value as long as the supplier uses the same currency. For bills with suppliers using a different currency than your default, you must include the currency value, matching the supplier's configured currency. To change the currency of a customer or vendor, a new one must be created with the desired currency. Foreign currencies can only be sent to suppliers configured with that currency.
billsOneOn bill line items, QuickBooks returns ClassRef.name as the FullyQualifiedName
(e.g. "Fruit:Apple") rather than the leaf class name. Apideck normalises this by
extracting the last : segment, so tracking_categories[].name returns "Apple" and
parent_name returns "Fruit". Expense line items are unaffected — QuickBooks returns
only the short name there.
Categories1 gotcha
categoriesAllQuickBooks Online does not expose a reliable cross-page total record count. meta.total_count will not appear. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
Credit Notes1 gotcha
creditNotesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
filter[updated_since] and filter[created_since] are exclusive (>) and Metadata.LastUpdatedTime / Metadata.CreateTime have second granularity, so a record whose timestamp equals the cursor to the exact second is skipped. For incremental sync, set the cursor one second behind the highest updated_at seen in the previous run and de-duplicate by id.
Customers3 gotchas
customersAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
customersAddQuickBooks supports only billing and shipping addresses. Therefore, when creating addresses, it is required to specify the type as 'billing' or 'shipping' in the address object within the addresses array.
customersUpdateQuickBooks supports only billing and shipping addresses. Therefore, when creating or updating addresses, it is required to specify the type as 'billing' or 'shipping' in the address object within the addresses array.
Departments1 gotcha
departmentsAllQuickBooks Online does not expose a reliable cross-page total record count. meta.total_count will not appear. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
Expenses2 gotchas
expensesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
expensesAddThe top-level account must be a bank or credit-card account — the payment source the money left from — not an expense account; the expense account goes on line_items[].account. Sending an expense account at the top level fails with 400 "Invalid account type used" (code 6430), an error that names neither the field nor the type it expected.
reference and memo both map to the single PrivateNote field: only one survives a write (the other is dropped with no error), and on read both are populated from it and are always identical. Send only one. Which of the two wins on write is currently under review — do not rely on it.
Invoice Items2 gotchas
invoiceItemsAddThe taxable field is applicable to US companies only and should be sent in the request body if your QuickBooks account is in the US region.
invoiceItemsUpdateThe taxable field is applicable to US companies only and should be sent in the request body if your QuickBooks account is in the US region.
Invoices5 gotchas
invoicesAllQuickBooks uses tax codes rather than tax rates. The tax_rate on line items references a tax code, which may not include the actual percentage value. To get the actual rate, retrieve the full tax rate details via the tax-rates endpoint.
invoicesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
invoicesAddQuickbooks offers limited (regional) support for applying discount on a Line Item. Including discount_percentage or discount_amount applies to entire invoice. The default type for a Line Item is a sales item if no type has been provided.
invoicesUpdateQuickbooks offers limited (regional) support for applying discount on a Line Item. Including discount_percentage or discount_amount applies to entire invoice. The default type for a Line Item is a sales item if no type has been provided. When setting status to void, do not include any other fields in the request body.
invoicesUpdateWhen setting tax rates on line items, QuickBooks requires valid tax codes. The tax_rate.id must reference an existing tax code from the tax-rates endpoint. QuickBooks automatically calculates tax amounts based on the tax code's rate.
Journal Entries4 gotchas
journalEntriesAllQuickBooks only returns journal entries that were explicitly created as JournalEntry records.
System-generated GL postings from invoices, bills, payments, deposits, transfers, and other
transaction types post to the general ledger but are not exposed by QuickBooks as journal entries
and will not appear in this response. To reconstruct full GL activity, fetch the underlying
transaction resources (invoices, bills, payments, etc.) in addition to journal entries.
journalEntriesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
journalEntriesAddQuickbooks only supports one tracking category at a time so only the first item in the tracking_categories list will be used. Line-level tax fields (tax_rate, tax_amount, tax_type) on journal entries are only supported for non-US QuickBooks companies (UK, CA, AU, etc.). US-based QuickBooks companies silently discard all tax fields — the request succeeds but no tax data is persisted. For US companies that need to reflect tax in journal entries, add a separate line item posting the tax amount to a tax liability ledger account (e.g., "Sales Tax Payable"). This keeps the journal entry balanced in the general ledger, but will not populate QuickBooks Sales Tax reports — for that, use invoices or sales receipts instead. When line_items[].tax_type is not set, QuickBooks requires knowing whether the tax applies to a sales or purchase transaction. Unify infers this from line_items[].type: credit lines are treated as sales (TaxApplicableOn: Sales) and debit lines as purchases (TaxApplicableOn: Purchase). This covers the common case of sales summary journal entries. For atypical entries (e.g. a credit to an AP account, or a debit for a sales return), set tax_type explicitly on each line to override the default.
journalEntriesUpdateQuickbooks only supports one tracking category at a time so only the first item in the tracking_categories list will be used. When line_items[].tax_type is not set, QuickBooks requires knowing whether the tax applies to a sales or purchase transaction. Unify infers this from line_items[].type: credit lines are treated as sales (TaxApplicableOn: Sales) and debit lines as purchases (TaxApplicableOn: Purchase). This covers the common case of sales summary journal entries. For atypical entries (e.g. a credit to an AP account, or a debit for a sales return), set tax_type explicitly on each line to override the default.
Ledger Accounts2 gotchas
ledgerAccountsAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
ledgerAccountsDeleteThis connector does not support deleting ledger accounts. Instead, it will update the ledger account to inactive.
Locations1 gotcha
locationsAllQuickBooks Online does not expose a reliable cross-page total record count. meta.total_count will not appear. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
Payments3 gotchas
paymentsAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
paymentsAddPayment allocations in QuickBooks are processed asynchronously. While the allocations are included in the request, they may not appear in the immediate response. The allocations will be applied and become visible in subsequent list or get calls.
paymentsUpdateTo clear the payment method on an existing payment, send payment_method_id: null explicitly
in the PATCH body. Omitting the field preserves the existing payment method (sparse update
semantics). Sending null triggers PaymentMethodRef: { value: null } in the QuickBooks
sparse POST, which removes the payment method reference from the payment.
Projects4 gotchas
projectsAllThe priority field is mapped from QuickBooks integer values (0-9) to unified enum values using ranges: 0-2 → "low", 3-5 → "medium", 6-7 → "high", 8-9 → "critical".
projectsAddThe priority field accepts enum values ("low", "medium", "high", "critical") which are converted to QuickBooks integer values: "low" → 2, "medium" → 5, "high" → 7, "critical" → 9.
projectsOneThe priority field is mapped from QuickBooks integer values (0-9) to unified enum values using ranges: 0-2 → "low", 3-5 → "medium", 6-7 → "high", 8-9 → "critical".
projectsUpdateThe priority field accepts enum values ("low", "medium", "high", "critical") which are converted to QuickBooks integer values: "low" → 2, "medium" → 5, "high" → 7, "critical" → 9.
Purchase Orders1 gotcha
purchaseOrdersAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
Quotes1 gotcha
quotesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
Refunds4 gotchas
refundsAlltax_inclusive only applies to UK, AU, IN, and CA editions. US companies ignore this field silently.
refundsAddtax_inclusive only applies to UK, AU, IN, and CA editions. US companies ignore this field silently. payment_method_id is required to set the payment method. Provide the ID of a payment method record configured in QuickBooks. total_amount is required on each line item. If not provided, it is computed from quantity * unit_price. tracking_categories behavior depends on company settings. "One to entire transaction" uses top-level tracking_categories. "One to each row" requires tracking_categories on each line item.
refundsOnetax_inclusive only applies to UK, AU, IN, and CA editions. US companies will not have this field in responses. payment_method returns the name of the payment method record, not the payment type category.
refundsUpdaterow_version is required for updates. tracking_categories behavior depends on company settings. "One to each row" requires tracking_categories on each line item.
Sales Receipts2 gotchas
salesReceiptsAddtax_inclusive only applies to UK, AU, IN, and CA editions. US companies ignore this field silently.
payment_method_id is required to set the payment method. Provide the ID of a payment method record configured in QuickBooks.
total_amount is required on each line item. If not provided, it is computed from quantity * unit_price.
tracking_categories behavior depends on company settings. "One to entire transaction" uses top-level tracking_categories. "One to each row" requires tracking_categories on each line item.
The deposit destination is controlled via account. Omit account to deposit to Undeposited Funds (QuickBooks' default).
Tax handling depends on the company's country edition. US companies with Automated Sales Tax calculate tax automatically by location: a submitted tax_code or total_tax overrides the automatic calculation, so omit both to accept it. Line item tax_rate values must be the pseudo-codes TAX or NON for US companies (other values are rejected with a validation error).
Non-US editions require real QuickBooks tax code IDs for tax_rate instead of the US pseudo-codes, and total_tax is recalculated from the line tax codes and cannot be overridden.
With multicurrency enabled, currency must match the customer's currency, and currency_rate is required when it differs from the company's home currency.
salesReceiptsUpdaterow_version submitted in the request body is ignored. The connector always fetches the latest version immediately before writing, so there is no optimistic-concurrency protection — concurrent updates are last-write-wins.
tax_inclusive only applies to UK, AU, IN, and CA editions. US companies ignore this field silently.
payment_method_id is required to set the payment method. Provide the ID of a payment method record configured in QuickBooks.
total_amount is required on each line item. If not provided, it is computed from quantity * unit_price.
tracking_categories behavior depends on company settings. "One to each row" requires tracking_categories on each line item.
The deposit destination is controlled via account. Omit account to deposit to Undeposited Funds (QuickBooks' default).
Tax handling depends on the company's country edition. US companies with Automated Sales Tax calculate tax automatically by location: a submitted tax_code or total_tax overrides the automatic calculation, so omit both to accept it. Line item tax_rate values must be the pseudo-codes TAX or NON for US companies (other values are rejected with a validation error).
Non-US editions require real QuickBooks tax code IDs for tax_rate instead of the US pseudo-codes, and total_tax is recalculated from the line tax codes and cannot be overridden.
With multicurrency enabled, currency must match the customer's currency, and currency_rate is required when it differs from the company's home currency.
Suppliers3 gotchas
suppliersAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
suppliersAddQuickBooks only supports a single billing address. Therefore, the first item in the addresses array will always be mapped as the billing address, regardless of its original type.
suppliersUpdateQuickBooks only supports a single billing address. Therefore, the first item in the addresses array will always be mapped as the billing address, regardless of its original type.
Tax Rates3 gotchas
taxRatesAllIn quickbooks, the tax rates resource does not support pagination. QuickBooks returns tax codes rather than complete tax rate data. The effective_tax_rate may not be populated; use code to reference the tax in invoice line items.
taxRatesAllQuickBooks Online does not expose a reliable cross-page total record count. The QueryResponse.totalCount field in list responses reflects the count for that page only, not the full dataset. meta.total_count will not appear in list responses. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.
taxRatesAddTo create a tax rate, effective_tax_rate, tax_payable_account_id, name and a component is required. If tax_payable_account_id is unknown, make a proxy call to get list of TaxAgency. TaxAgency doc
Tracking Categories1 gotcha
trackingCategoriesAllQuickBooks Online does not expose a reliable cross-page total record count. meta.total_count will not appear. Surfacing the true total requires a separate SELECT COUNT(*) FROM {Entity} query — an extra API call that is not currently implemented.