Integrations
QuickBooks SDK: get started
Use the complete versioned QuickBooks Online Accounting and Payments contracts through Alter
Alter maintains the provider contract, generates both SDKs, and builds each provider request on the server. The application supplies an operation and its input. The authorized connection determines the company and environment. An agent is optional: a payroll application uses an ordinary App client and a grant for each connected customer.
Install
Section titled “Install”npm install @alter-ai/sdk @alter-ai/quickbooks# Python (installs core automatically)pip install alter-sdk-quickbooksThe provider package includes only QuickBooks types and response schemas and pins its contract version.
Browse the complete API reference for every method’s input fields, response models, TypeScript and Python examples, and policy identity. This provider’s API reference in the Integrations sidebar groups operations by resource. Download the pinned OpenAPI specifications for Accounting and Payments.
Connect and call
Section titled “Connect and call”Configure QuickBooks OAuth, complete Connect consent for the customer, and retain the returned grant ID. Accounting requires com.intuit.quickbooks.accounting; Payments independently requires com.intuit.quickbooks.payment. A user’s subscription, country, Payments enrollment, and Intuit app approval still determine which operations Intuit permits.
import { App } from "@alter-ai/sdk";import { QuickBooksIntegration, quickbooksQueryPage } from "@alter-ai/quickbooks";const app = new App({ apiKey: process.env.ALTER_API_KEY! });try { const qb = new QuickBooksIntegration(app, { grantId: process.env.QUICKBOOKS_GRANT_ID! }); const call = await qb.account.query({ query: { query: quickbooksQueryPage("SELECT * FROM Account", 1, 100) }, }); const result = await call.wait(); // Polls an approval if required; never resubmits. console.log(result.bodyJson().QueryResponse?.Account);} finally { await app.close();}import asyncio, osfrom alter_sdk import Appfrom alter_sdk_quickbooks import QuickBooksIntegration, quickbooks_query_page
async def main(): async with App(api_key=os.environ["ALTER_API_KEY"]) as app: qb = QuickBooksIntegration(app, {"grant_id": os.environ["QUICKBOOKS_GRANT_ID"]}) call = await qb.account.query({"query": { "query": quickbooks_query_page("SELECT * FROM Account", 1, 100) }}) result = await call.wait() print(result.body_json().get("QueryResponse", {}).get("Account", []))
asyncio.run(main())The connection options retain Alter’s existing grant/account/label addressing and verified user-token semantics. Do not send a company ID, URL, OAuth token, environment override, or Authorization header as operation arguments. The server rejects routing overrides and a grant for another provider.
Full operation coverage
Section titled “Full operation coverage”The generated reference lists every supported operation and both SDK method names. Contract 2026-10-20 covers 261 executable variants: the 259 documented Accounting and Payments entries include two entries with alternative regional routes. It includes CRUD, full/sparse updates, queries/counts, reports, CDC, batch, recurring transactions, attachments, PDFs, Payments cards, bank accounts, charges, echecks, tokens, and receipts. This is QuickBooks Online; Desktop’s qbXML protocol is separate.
Generated methods pin their contract version automatically. The generic method requires an explicit version:
const response = await app.integrations.execute({ integration: "quickbooks", version: "2026-10-20", operation: "quickbooks.account.read_an_account", grantId: process.env.QUICKBOOKS_GRANT_ID!, arguments: { path: { accountId: "42" } },});Execution never silently chooses the latest version. Discovery may default to latest. An unavailable version returns ManagedOperationError with unknown_contract_version (409). Deploy a backend containing a contract before publishing clients that select it; retain old contracts while clients or approvals depend on them.
Querying and numeric values
Section titled “Querying and numeric values”Queries use Intuit’s native SQL-like language. Use quickbooksQueryLiteral / quickbooks_query_literal to quote string values; never interpolate untrusted values directly. Use the page helper to append STARTPOSITION and MAXRESULTS. Positions start at one and Intuit returns at most 1,000 entities per query. Advance explicitly; there is no hidden pagination or extra API call. Query/count methods enforce the selected entity. Reports and CDC retain their documented native arguments and result envelopes.
Supply exact monetary values and large identifiers as strings where the schema permits them. Typed result decoding preserves decimal/exponent tokens and integers beyond JavaScript’s safe integer range as strings in both SDKs. Safe integers remain numbers. Choose an exact decimal library before arithmetic. Raw response bytes/text remain available unchanged. Dates and provider references retain their provider wire representation.
Updates, batches, and retries
Section titled “Updates, batches, and retries”Updates/deletes carry the entity Id and current SyncToken; sparse updates add sparse: true. Fetch the current record when Intuit reports a stale token and reconcile the intended change before another write. Delete, void, and send are distinct managed operations.
Batch requests accept up to 30 items, following Intuit’s documented recommendation. Each item has a unique bId. Alter evaluates every constituent read/write/delete/void against policy before sending the batch once. A child denial rejects the entire batch; approval gates are collected only after every item is checked. Quota rules count the single admitted HTTP request. Provider batch responses preserve each item’s result or fault; HTTP 200 alone does not establish every item’s success.
Neither SDK automatically resubmits managed calls. Approved writes are dispatched at most once after provider contact: a timeout, broken connection, or recovered worker reports provider_outcome_unknown instead of replaying the write. Capacity or DNS refusals that prove no provider contact may use the existing approval-worker retry path; GET/HEAD/OPTIONS operations classified as pure reads also retain that path. Inspect the provider request ID and reconcile the record before repeating it. Accounting’s query.requestid and Payments’ documented headers["request-Id"] are passed through when present; retain the same request ID when following Intuit’s documented replay procedure. Alter does not invent idempotency guarantees for operations that do not document them.
Amount policies use writable amounts, including Payment/BillPayment TotalAmt and Transfer/CreditCardPayment Amount. QuickBooks recomputes totals for invoices, receipts and other line-based transactions, so their caller-supplied TotalAmt is never trusted for authorization. An amount-dependent rule fails closed when the actual amount cannot be determined, including inside batches and recurring transactions. Operation-level policies remain available for these transactions.
Files and non-JSON responses
Section titled “Files and non-JSON responses”Upload uses a signed JSON envelope with body.files: each file has filename, content_type, content_base64, and optional native Attachable metadata. The server validates the envelope and constructs multipart parts. Both envelope and encoded request obey Alter’s existing 5 MiB request limit. Approvals show metadata, filename, byte length, and SHA-256 of the exact frozen binary; file contents are not rendered in the approval card.
Use result.bodyBytes() / result.body_bytes() for PDFs, including Payments receipts, and bodyText() / body_text() for Entitlements XML. Attachment download operations preserve Intuit’s native response, including a temporary download URL where returned; Alter does not automatically follow a URL from response content. Treat temporary URLs as sensitive. On attachment updates and deletes, Alter removes the read-only TempDownloadUri and ThumbnailTempDownloadUri fields before policy evaluation, approval storage and provider dispatch, so ordinary read-modify-write requests remain usable. Typed JSON decoding is for successful JSON responses only; provider failures raise ProviderAPIError while retaining the raw response on the result object.
Payments may contain sensitive card/bank information. Managed Payments request/response body capture is disabled; metadata audit remains active. An approval-requiring call with raw card or bank details returns sensitive_payment_input_requires_token before freezing. Use a payment token or card-on-file reference for that workflow. Immediate authorized operations still support the documented raw input schema.
CLI and portal
Section titled “CLI and portal”# ALTER_API_KEY supplies a runtime key; ALTER_USER_TOKEN can carry user attribution.alter integrations listalter integrations operations quickbooks --version 2026-10-20alter integrations execute quickbooks quickbooks.account.read_an_account \ --version 2026-10-20 --grant "$QUICKBOOKS_GRANT_ID" \ --input '{"path":{"accountId":"42"}}' --waitUse --input @request.json or --input - for stdin. --output-file receipt.pdf writes completed response bytes to a new owner-only file and refuses overwrites. Without --wait, a required approval returns pending state and its ID. The command does not repeat execution while waiting.
The existing provider operation view has a Managed SDK operations card with contract version, search, and input/output schemas. Policy authoring continues to use canonical policy operation IDs in the generated reference. Approvals and audits record the managed operation and selected contract version.
Existing API requests
Section titled “Existing API requests”app.request and agent.request remain available for custom requests, provider extensions, and dynamic tools. Switching a call to a managed method does not change grant permissions, tenant isolation, authentication, key admission, quotas, revocation, or policy enforcement. It transfers provider request construction and versioned schema maintenance to Alter.
Typed result decoding stays bound to the operation and contract version selected when the call began, including after approval. JSON decoding rejects incompatible documented shapes and reports QuickBooks Fault envelopes, including batch-item faults returned with HTTP 200. Additional provider fields and new output enum values remain readable. Raw response bytes remain available for reconciliation; a decoding error never resubmits the operation. Wallet approvers see the frozen managed operation and contract version alongside the policy-evaluated request.
Managed QuickBooks requests and responses are excluded from payload-body capture, including Accounting, Payments, batch, query and CDC responses that may contain tax identities or bank details. Metadata audit remains enabled. Requests containing SSN, vendor/customer tax identifiers, bank account numbers or vendor bank details cannot be frozen for approval; use provider-held references or an immediately authorized operation.
Resume after a restart
Section titled “Resume after a restart”Persist call.approvalId (TypeScript) or call.approval_id (Python), then
construct a fresh provider client and call resume(savedId), followed by wait().
The stored approval selects the operation; this installed package verifies its
provider and contract version before attaching the response validator. Mismatches
raise ManagedOperationError, never silently decode using another contract.
See persist-and-resume examples.
Rules for SDK functions
Section titled “Rules for SDK functions”Policy operation fields also accept the published SDK function IDs listed by
alter integrations operations <provider>. Use when.operation for a
json_match or conditional require_approval rule, or match.operations for
content_match (including redaction and step-up). Conditional approval can also
use when.match.operations with parameter conditions. alter policy simulate --operation <function-id> tests that exact function.
Managed calls carry a server-verified function identity. Alter still evaluates policy against the actual method, URL and body after building the request from the authorized connection. Existing endpoint, method, host, catalog-operation and family rules continue to apply unchanged.
A raw call can share an endpoint with several SDK functions. It matches all
of those function IDs: a deny or approval rule naming any one of them applies.
A function name never grants permission or bypasses existing restrictions;
Alter’s policy rules only narrow access and do not accept an allow effect.
The portal’s operation picker lists searchable SDK names grouped by product,
alongside the existing catalog operations. alter providers operations list
shows the functions covered by each catalog operation.
For example, this rule requires approval for quickbooks.account.full_update_an_account:
{ "effect": "require_approval", "when": { "operation": "quickbooks.account.full_update_an_account" }, "approval": { "approvers": ["reviewer@example.com"] }}Save it with alter policy rules create --app <app-id> --grant <grant-id> --type require_approval --body @rule.json, or select the function in the portal.
quickbooks.account.create_an_account and
quickbooks.account.full_update_an_account share POST /account. The update
rule above holds a managed update without holding a managed create. A raw
POST /account is held because it could perform either function. Existing
accounts/create rules continue to cover both.
Sensitive input refusals use sensitive_payment_input_requires_token for bank
and raw card fields. Other sensitive inputs, including tax identities and birth
dates, return sensitive_input_not_retained in both SDKs. Neither error contains
the rejected value.