QuickBooks Online ExecModule
Overview
QuickBooksOnlineModule connects ValkyrAI workflows to the QuickBooks Online Accounting API through the native map I/O ExecModule ABI. Workflow Studio discovers it as QuickBooksOnlineModule; the OAuth access token and numeric QuickBooks company realm ID resolve only from an encrypted IntegrationAccount.
The first production operation set focuses on the accounting path from customer to receivable to payment:
get_company_infolist_customers,get_customer,create_customer,update_customerlist_invoices,get_invoice,create_invoice,update_invoice,send_invoicelist_payments,get_payment,create_payment
QuickBooks query pagination is numeric and bounded. Only GET requests retry automatically. Customer, invoice, payment, and delivery writes run once so an ambiguous timeout cannot duplicate or resend financial activity.
Usage
- Create an Intuit application and authorize the
com.intuit.quickbooks.accountingscope. - Store the current OAuth access token in the encrypted
apiKeyfield of anIntegrationAccount. - Store the numeric QuickBooks company realm ID in
IntegrationAccount.accountIdand set status toREADY. - Bind that account through
ExecModuleConfig.authConfig.integrationAccount. - Use
get_company_infoto verify the intended company before financial mutations. - Read the latest resource and retain its
SyncTokenbefore an update. - Reconcile QuickBooks state before repeating any write after an ambiguous connection failure.
Workflow input cannot provide an OAuth token, realm ID, or arbitrary endpoint. The module routes only to the fixed production or sandbox QuickBooks Online hosts.
Inputs
| Name | Type | Requirement | Default | Description and constraints |
|---|---|---|---|---|
operation | string | Required | None | One of the 13 documented operations. |
resourceId | string | Get, update, and send operations | None | Numeric QuickBooks entity ID, maximum 32 digits. |
syncToken | string | Customer/invoice update | None | Numeric optimistic-concurrency token from the latest entity read. |
customer | object or JSON string | Customer create/update | None | Allowlisted customer fields, 512 KiB maximum. |
invoice | object or JSON string | Invoice create/update | None | Allowlisted invoice fields and 1–1,000 lines, 512 KiB maximum. |
payment | object or JSON string | Payment create | None | Allowlisted payment fields; positive amount and optional linked-transaction lines. |
email | string | send_invoice | None | Valid bounded recipient address, maximum 254 characters. |
environment | string | Optional | production | production or sandbox; maps to a fixed Intuit host. |
minorVersion | integer | Optional | 75 | QuickBooks Accounting API minor version from 75 through 999. |
startPosition | integer | Optional list continuation | 1 | One-based query start position. |
limit | integer | Optional | 100 | Maximum emitted resources, 1–10,000. |
returnAll | boolean | Optional | false | Continue 1,000-record query pages until exhaustion or the result cap. |
Customer payloads accept only DisplayName, GivenName, MiddleName, FamilyName, CompanyName, PrimaryEmailAddr, PrimaryPhone, BillAddr, ShipAddr, Notes, Taxable, PreferredDeliveryMethod, CurrencyRef, ParentRef, Job, and Active.
Invoice payloads accept only CustomerRef, Line, TxnDate, DueDate, DocNumber, PrivateNote, CustomerMemo, BillEmail, BillEmailCc, BillEmailBcc, SalesTermRef, DepositToAccountRef, CurrencyRef, ExchangeRate, DepartmentRef, ClassRef, TxnTaxDetail, ApplyTaxAfterDiscount, PrintStatus, EmailStatus, AllowOnlineACHPayment, and AllowOnlineCreditCardPayment.
Payment payloads accept only CustomerRef, TotalAmt, Line, TxnDate, PaymentMethodRef, DepositToAccountRef, PaymentRefNum, PrivateNote, CurrencyRef, ExchangeRate, ARAccountRef, and TxnSource.
Outputs
| Name | Type | When present | Description |
|---|---|---|---|
status | string | Always | success or error. |
operation | string | Always | Normalized operation name. |
attempts | integer | Always | Provider attempts across all pages. |
httpStatus | integer | Provider responded | Last QuickBooks HTTP status. |
data | object | Single-resource/write success | Provider company, customer, invoice, or payment. |
Id, SyncToken, DocNumber | string | Provider returns field | Safe convenience identity fields. |
items / count | array / integer | List success | Bounded entity results and emitted count. |
hasMore | boolean | List success | Whether another numeric query page may exist. |
nextStartPosition | integer | Another page may exist | One-based continuation position. |
requestId | string | Intuit returns one | Safe intuit_tid or request trace reference. |
error | object | Failure | Safe {code, message, httpStatus?, retryable} details. |
OAuth tokens and authorization headers never enter outputs. Provider messages pass through ValkyrAI's workflow sensitive-data policy.
IntegrationAccount Requirements
| Setting | Requirement |
|---|---|
| Provider | Intuit QuickBooks Online OAuth 2.0 application |
| Scope | com.intuit.quickbooks.accounting |
accountId | Numeric company realm ID returned by Intuit OAuth |
apiKey | Current OAuth access token in an encrypted SecureField |
password | Legacy encrypted token fallback only; prefer apiKey |
status | READY or legacy unset status; CLOSED and ERROR fail closed |
OAuth authorization-code exchange, refresh-token storage, token refresh, revocation, and rotation belong to the platform integration-account lifecycle. Workflow inputs never handle OAuth secrets.
Configuration
{
"version": "1.0.0",
"authConfig": {
"authStrategy": 1,
"integrationAccount": "integration-account:quickbooks-revenue-ops"
},
"retryPolicy": {
"maxAttempts": 3,
"backoffStrategy": "EXPONENTIAL",
"initialDelayMs": 1000,
"maxDelayMs": 60000,
"jitter": false
},
"executionConfig": {"timeoutMs": 30000},
"payloadConfig": {
"parameters": "{\"operation\":\"list_invoices\",\"environment\":\"production\",\"limit\":100}"
}
}
The integration-account value is symbolic. Persisted workflows use the generated relationship rather than a plaintext token or realm identifier.
Operations
| Operation | QuickBooks behavior | Side effect |
|---|---|---|
get_company_info | Reads the bound company profile. | Read-only; safe retries. |
list_customers | Runs a bounded Customer query. | Read-only; safe retries. |
get_customer | Reads one customer by numeric ID. | Read-only; safe retries. |
create_customer | Creates one allowlisted customer; DisplayName is required. | New accounting entity; single attempt. |
update_customer | Applies a sparse update with caller-supplied Id and SyncToken. | Accounting mutation; single attempt. |
list_invoices | Runs a bounded Invoice query. | Read-only; safe retries. |
get_invoice | Reads one invoice by numeric ID. | Read-only; safe retries. |
create_invoice | Creates one customer invoice with bounded lines. | New receivable; single attempt. |
update_invoice | Applies a sparse invoice update with explicit concurrency token. | Financial mutation; single attempt. |
send_invoice | Sends one invoice to the validated email recipient. | External delivery; single attempt. |
list_payments | Runs a bounded Payment query. | Read-only; safe retries. |
get_payment | Reads one payment by numeric ID. | Read-only; safe retries. |
create_payment | Records a positive customer payment and optional invoice links. | Financial mutation; single attempt. |
Errors and Failure Modes
| Code | Typical cause | Retryable | Resolution |
|---|---|---|---|
VALIDATION_ERROR | Missing/invalid realm, ID, token, email, payload, reference, line, or pagination bound. | No | Correct input; no unsafe request was sent. |
UNSUPPORTED_OPERATION | Unknown operation. | No | Select a documented operation. |
INTEGRATION_ACCOUNT_REQUIRED | No bound account. | No | Bind a QuickBooks IntegrationAccount. |
INTEGRATION_ACCOUNT_NOT_READY | Account is closed/error. | No | Repair or reconnect the account. |
QUICKBOOKS_HTTP_400 | Intuit rejected an entity field or Accounting API rule. | No | Inspect the safe fault detail and correct the request. |
QUICKBOOKS_HTTP_401 / 403 | Access token invalid/expired or scope/company access missing. | No | Refresh/re-authorize the IntegrationAccount. |
QUICKBOOKS_HTTP_404 | Entity is absent or invisible in the bound realm. | No | Re-read/list with the same account and realm. |
QUICKBOOKS_HTTP_409 | Stale SyncToken or business-rule conflict. | No | Read the current entity and rebuild the update. |
QUICKBOOKS_HTTP_429 / 5xx | Rate limit or transient provider failure. | Yes for reads | Honor Retry-After; reconcile writes before repeating them. |
NETWORK_ERROR | Timeout, DNS, TLS, or connectivity failure. | Yes for reads | Verify connectivity and provider state. |
RESPONSE_TOO_LARGE | Response exceeded 5 MiB. | No | Lower the limit or split the query. |
INVALID_PROVIDER_RESPONSE | Expected entity or query array was absent/invalid. | No | Use requestId to verify provider/API compatibility. |
Example
Create one approved invoice:
{
"operation": "create_invoice",
"invoice": {
"CustomerRef": {"value": "42"},
"TxnDate": "2026-08-08",
"DueDate": "2026-09-07",
"PrivateNote": "ValkyrAI workflow milestone valkyr-4404",
"Line": [
{
"Amount": 250,
"DetailType": "SalesItemLineDetail",
"Description": "Workflow automation milestone",
"SalesItemLineDetail": {
"ItemRef": {"value": "7"},
"Qty": 1,
"UnitPrice": 250
}
}
]
}
}
Expected result:
{
"status": "success",
"operation": "create_invoice",
"attempts": 1,
"httpStatus": 200,
"Id": "145",
"SyncToken": "0",
"DocNumber": "1001",
"data": {
"Id": "145",
"SyncToken": "0",
"DocNumber": "1001"
}
}
Notes
- Pagination: list operations generate only
SELECT * FROM <allowlisted entity> STARTPOSITION n MAXRESULTS m. Provider-returned URLs and arbitrary caller SQL are never followed or executed. Pages are capped at 1,000 items and total output at 10,000. - Rate limits: reads retry HTTP 408, 429, 500, 502, 503, and 504 according to
RetryPolicy, honoring numericRetry-After. Writes never retry automatically. - API limits: provider responses are capped at 5 MiB, structured payloads at 512 KiB, and invoice/payment line arrays at 1,000 entries.
- Minor versions: the default is 75 because Intuit discontinued minor versions 1–74. Change it only after validating the target schema and compatibility.
- Idempotency: creates, updates, payment recording, and invoice delivery are single-attempt. Use caller-owned
DocNumber,PaymentRefNum, or workflow correlation fields where appropriate and reconcile provider state after ambiguous failures. - Concurrency: updates require the latest
SyncToken; the module never hides a preliminary provider read inside a financial mutation. - Destructive behavior: this release exposes no delete, void, refund, credit memo, bill-payment, or transaction-journal operations. Customer deactivation is an explicit sparse update and remains subject to QuickBooks rules.
- API behavior: QuickBooks can apply company preferences, taxes, multicurrency, custom transaction numbers, rounding, and linked-transaction rules beyond local structural validation.
- Security: credentials remain in IntegrationAccount SecureFields. Fixed-host routing, numeric realm/ID validation, allowlisted entity fields, bounded responses, and redacted fault details prevent arbitrary routing or token reflection.
- External verification: request construction, query pagination, validation, concurrency fields, retry safety, redaction, response mapping, and metadata discovery have deterministic local tests. Live Intuit OAuth scopes, company preferences, taxation, email delivery, rate limits, and accounting effects require separately authorized provider credentials and are not exercised in repository tests.
- Deferred operations: vendors, bills, purchases, estimates, items, employees, reports, attachments, PDFs, batch requests, CDC, webhooks/triggers, refunds, credit memos, deposits, journal entries, OAuth refresh, arbitrary queries, and destructive operations.
- Functional references: n8n QuickBooks node source, Intuit Accounting API, and Intuit minor versions.