Skip to content
Desktop Accounting API

Passthrough and raw qbXML

The typed operations cover the QuickBooks objects most integrations need. qbXML, QuickBooks’ own request language, covers more: deleting list objects, data extensions, to-dos, vehicle mileage, billing rates and other messages. Passthrough sends any qbXML request to the end user’s QuickBooks and returns QuickBooks’ response, with the same queue, request status, idempotency and error handling as every other call.

POST /v1/end-users/{endUserId}/passthrough/quickbooks_desktop

The end user comes from the path, so no Daapi-End-User-Id header is needed.

Send an object whose keys are qbXML request element names. We build the qbXML in the order the schema requires, so you do not need to get element order right.

Terminal window
curl https://api.desktopaccountingapi.com/v1/end-users/eu_01j9.../passthrough/quickbooks_desktop \
-H "Authorization: Bearer $DAAPI_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{ "CustomerQueryRq": { "MaxReturned": "5", "ActiveStatus": "ActiveOnly" } }'
{
"CustomerQueryRs": {
"@statusCode": "0",
"@statusSeverity": "Info",
"@statusMessage": "Status OK",
"CustomerRet": [
{ "ListID": "80000001-1730311000", "Name": "Acme Supply", "IsActive": "true" }
]
}
}

Conventions in both directions:

  • XML attributes become keys starting with @, such as "@statusCode" and "@iterator".
  • An element that the schema allows to repeat is an array, even with one item.
  • Values are strings, exactly as qbXML writes them ("true", "125.00"). Passthrough does not apply the typed API’s conversions.

Send Content-Type: application/xml with a <QBXMLMsgsRq> fragment and get the raw <QBXMLMsgsRs> back:

Terminal window
curl https://api.desktopaccountingapi.com/v1/end-users/eu_01j9.../passthrough/quickbooks_desktop \
-H "Authorization: Bearer $DAAPI_SECRET_KEY" \
-H "Content-Type: application/xml" \
--data-binary '<QBXMLMsgsRq><CustomerQueryRq><MaxReturned>5</MaxReturned></CustomerQueryRq></QBXMLMsgsRq>'

We add the <?qbxml?> header, the <QBXML> envelope and onError="stopOnError" unless you set onError yourself. The qbXML version is the one negotiated with the end user’s QuickBooks.

A body that contains any message other than a query (...QueryRq) is a write. For writes:

  • Send an Idempotency-Key. The fingerprint covers the generated qbXML, so the same key with a different message returns 422 IDEMPOTENCY_KEY_REUSED.
  • We add a newMessageSetID so the result can be checked if the response is lost. The same outcome rules apply.

Example: delete a customer, which the typed API handles by deactivation instead.

{
"ListDelRq": {
"ListDelType": "Customer",
"ListID": "80000042-1730313843"
}
}

Passthrough answers 200 with each message’s own @statusCode, @statusSeverity and @statusMessage, even when one message failed. You read the statuses yourself. Two cases return an error instead:

  • 400 PASSTHROUGH_INVALID_QBXML: the body cannot become valid qbXML, for example an unknown element.
  • No message was processed at all, for example because the connection is offline or QuickBooks could not open the file. You get the same connection errors as any other call.

With several messages and stopOnError, messages after a failed one return status 3231 (not processed).

  • A qbXML message has no typed operation, such as ListDel, DataExtMod, ToDoAdd, VehicleMileageAdd, TransferInventoryAdd or BillingRateQuery.
  • You need a qbXML option the typed operation does not expose.
  • You are porting existing qbXML code and want to move it over before rewriting it.

Prefer typed operations where they exist. They validate input before anything is queued, handle decimals, dates and text encoding for you, paginate safely, and map QuickBooks errors to specific codes.

Passthrough is billed like any other data request, and it counts toward rate limits.