This skill provides production-grade workflows, JSON schemas, and code patterns for integrating with the QuickBooks Online (QBO) REST API (v3) and the QuickBooks Payments API (v4).
EnvironmentAccounting API Base URLSandboxhttps://sandbox-quickbooks.api.intuit.comProductionhttps://quickbooks.api.intuit.com
All requests require the header Authorization: Bearer <access_token> and Accept: application/json.
Detailed schemas and code implementations are in the references/ folder. Load them as needed:
FileWhen to Readreferences/authentication.mdOAuth 2.0 flow, token exchange, token refresh, distributed lockingreferences/accounting_entities.mdCustomer, Invoice, Payment, Bill, JournalEntry CRUD payloadsreferences/webhooks.mdCloudEvents v1.0 payload, HMAC-SHA256 signature verification, async queue patternreferences/queries_and_errors.mdIDS-QL syntax, pagination, SQL injection prevention, exponential backoffreferences/ai_and_mcp.mdQuickBooks MCP server deployment, LangGraph agent state machines
text
[User clicks "Connect to QuickBooks"]
|
v
[Redirect to Intuit Authorization URL]
|
v
[User grants consent → receives ?code=...]
|
v
[POST /oauth2/v1/tokens/bearer (code exchange)]
|
v
[Store access_token (60 min) + refresh_token (100 days)]
|
v
[On 401 → POST /oauth2/v1/tokens/bearer (refresh grant)]
Critical: Encrypt both tokens at rest with AES-256-GCM. Use a distributed lock (e.g., Redis Redlock) to prevent concurrent refresh races.
QuickBooks uses optimistic locking. Every entity carries a SyncToken. If another process updated the entity since your last read, the API returns error 2030 (Stale Object).
text
[POST update with local SyncToken]
|
+----+----+
| |
200 OK 400 / 2030
| |
[Done] [GET entity → get new SyncToken]
|
[Merge changes]
|
[POST update again]
QuickBooks requires an HTTP 200 OK response within 3 seconds.
text
[Incoming POST from Intuit]
|
v
[1. Verify HMAC-SHA256 signature] ← raw bytes only, never parsed JSON
|
v
[2. Push raw payload to message queue (SQS / RabbitMQ / Redis)]
|
v
[3. Return HTTP 200 immediately]
|
v
[4. Background worker processes event]
EntityEndpointMethodsCustomer/v3/company/<realmId>/customerPOST (create), POST (update sparse), GETVendor/v3/company/<realmId>/vendorPOST, GETInvoice/v3/company/<realmId>/invoicePOST, GET, DELETE (void)Payment/v3/company/<realmId>/paymentPOST, GETBill/v3/company/<realmId>/billPOST, GETCreditMemo/v3/company/<realmId>/creditmemoPOST, GETJournalEntry/v3/company/<realmId>/journalentryPOST, GETAccount (CoA)/v3/company/<realmId>/accountPOST, GETItem/v3/company/<realmId>/itemPOST, GETDeposit/v3/company/<realmId>/depositPOST, GETTransfer/v3/company/<realmId>/transferPOST, GET
ReportEndpointKey ParamsProfit & Loss/v3/company/<realmId>/reports/ProfitAndLoss``start_date, end_date, accounting_methodBalance Sheet/v3/company/<realmId>/reports/BalanceSheet``date, accounting_methodGeneral Ledger/v3/company/<realmId>/reports/GeneralLedgerDetail``start_date, end_date, columnsA/R Aging/v3/company/<realmId>/reports/AgedReceivables``report_date, aging_method
Reports cell limit: 400,000 cells per response. Enforce a maximum 6-month date range per request to avoid timeouts.
OperationEndpointTokenize cardPOST https://api.intuit.com/quickbooks/v4/payments/tokensCreate chargePOST https://api.intuit.com/quickbooks/v4/payments/chargesRefund chargePOST https://api.intuit.com/quickbooks/v4/payments/charges/<id>/refunds
Bundle up to 30 independent operations into a single POST request:
text
POST /v3/company/<realmId>/batch
Retrieve all changed entities since a given timestamp:
text
GET /v3/company/<realmId>/cdc?entities=Customer,Invoice&changedSince=2026-05-31T00:00:00Z
Before going live, verify:
HTTP 429, 100 req/min limit).HTTP 200 within 3 seconds (async queue pattern).