Skip to content
Desktop Accounting API

Request lifecycle and status

Every call that needs QuickBooks Desktop (any /v1/quickbooks-desktop/ operation, the health check and passthrough) becomes a request with an ID such as req_01j9x4m6v4c8k2t7q0r5s3w1zb. The ID comes back in the Daapi-Request-Id header of every response, success or error. You can read the request at any time with GET /v1/requests/{id}, and the dashboard request log shows the same data.

Calls rejected before they are queued, for example a validation error, a connection that has not finished setup or a disabled connection, are in the log too: a failed request with sentAt: null and the error code. They are logged when the call names an end user of the project that has a connection, which exists from its first auth session. Rate-limited calls and calls without a valid end user ID are not logged; keep the requestId from their error body.

QuickBooks Desktop runs on your customer’s computer and cannot accept inbound connections. The QuickBooks Web Connector on that computer polls us instead. A request therefore waits in a queue for its connection until the Web Connector picks it up:

  1. Queued. We validate your call, translate it to qbXML and add it to the queue for that end user’s company file.
  2. Check-in. The Web Connector checks in. When work is waiting, it opens a QuickBooks session with the company file.
  3. Sent. The Web Connector passes the request to QuickBooks. From this point the request may change the company file.
  4. Answered. QuickBooks returns its response. We map it to JSON and finish the request as succeeded or failed.

QuickBooks handles one request at a time per company file. Requests for one connection run in the order you sent them. Requests for different end users run independently.

Situation Typical wait before QuickBooks starts on your request
Session already open (another request in the last 2 seconds, or a cursor read in the last 10 seconds) Under a second
Connection idle Up to 10 seconds, until the next check-in
Active in the last 10 minutes, session closed Up to 3 seconds
No requests for 7 days Up to 30 seconds for the first request
QuickBooks closed, “always allow” access granted Add the time QuickBooks needs to start, often 10 to 60 seconds

After a request finishes, the session stays open for about 2 seconds so a follow-up request skips the check-in wait. While a cursor has more pages, the session stays open for its 10-second idle window. A busy session closes after 2 minutes of continuous work and reopens at the next check-in, so other Web Connector applications on the same computer get their turn. While a session is open, QuickBooks treats the company file as in use by your app: closing the company, exiting QuickBooks or restoring a backup works again once the session closes, normally about 2 seconds after the last request. Send related requests back to back, and finish or abandon a cursor promptly, so the file is released quickly. If your customer sees QuickBooks refuse to close the file, send them QuickBooks says the company file is being used by another application.

QuickBooks itself sets the speed of large reads and reports. Page large lists (Pagination) and filter reports by date.

By default your HTTP call waits for QuickBooks’ answer, up to Daapi-Timeout-Seconds seconds. The default is 90 seconds (60 for the health check); you can send any integer from 1 to 300.

What happens Response
QuickBooks answered 200 or 201 with the result, or the mapped error
The end user has not finished setup 409 INTEGRATION_CONNECTION_NOT_SET_UP, immediately
The Web Connector has not checked in for over a minute 503 INTEGRATION_CONNECTION_NOT_ACTIVE, immediately, and nothing is queued
The Web Connector reported a QuickBooks error while your request waited (for example QuickBooks could not start, or the wrong file is open) That error at once, such as 503 QBD_CANNOT_START. Nothing was sent. QBD_STARTING keeps waiting instead.
The Web Connector opened a session but QuickBooks has not answered it for 60 seconds (20 seconds if an earlier session already went unanswered) 503 QBD_QUICKBOOKS_NOT_RESPONDING with details.diagnosis. Usually a dialog is open in QuickBooks. Nothing was sent.
The deadline passed before the request was sent 504 REQUEST_TIMEOUT_NOT_SENT with details.diagnosis. The request is canceled and never reaches QuickBooks. Safe to retry.
The deadline passed after the request was sent 504 QBD_REQUEST_TIMEOUT with outcome: "pending" and details.requestId. The request keeps running. Do not resend; read the result instead.

The last row matters for writes. QuickBooks may still be applying your invoice when your HTTP call gives up. Resending would create a second invoice. Collect the result instead:

Terminal window
curl "https://api.desktopaccountingapi.com/v1/requests/req_01j9...?waitSeconds=60" \
-H "Authorization: Bearer $DAAPI_SECRET_KEY"

waitSeconds (0 to 60) holds the call open until the request finishes, so you need no polling loop. The result field holds exactly the body the original call would have returned. The SDKs do this automatically when they receive QBD_REQUEST_TIMEOUT, and raise a pending error with the request ID only if their own timeout runs out first.

For imports, background syncs and anything else where nobody is waiting, send Prefer: respond-async. The API answers 202 Accepted at once with the request resource, a Location: /v1/requests/{id} header and Preference-Applied: respond-async.

Terminal window
curl https://api.desktopaccountingapi.com/v1/quickbooks-desktop/customers \
-H "Authorization: Bearer $DAAPI_SECRET_KEY" \
-H "Daapi-End-User-Id: eu_01j9..." \
-H "Idempotency-Key: 0f8c2a3e-6d1b-4b8e-9a51-2f6c7d9e4a10" \
-H "Prefer: respond-async" \
-H "Daapi-Queue-Ttl-Seconds: 7200" \
-H "Content-Type: application/json" \
-d '{"name":"Northwind Traders"}'
HTTP/1.1 202 Accepted
Location: /v1/requests/req_01j9x4m6v4c8k2t7q0r5s3w1zb
Preference-Applied: respond-async
Daapi-Request-Id: req_01j9x4m6v4c8k2t7q0r5s3w1zb

An async request waits for the connection even while the computer is off: its status changes to waiting_for_connection when the Web Connector goes offline and back to queued at the next check-in. Daapi-Queue-Ttl-Seconds (10 to 86400, default 3600) sets the latest moment it may still be sent. If the connection does not come back in time, the request ends as failed with REQUEST_EXPIRED and a diagnosis, never having reached QuickBooks. Async requests are not affected by the 60-second unanswered-session rule; they keep waiting until their queue lifetime ends or QuickBooks failed three sessions in a row.

Find out when it finishes in either of two ways:

  • Webhooks. Subscribe to request.succeeded and request.failed. See Webhooks.
  • Polling. Call GET /v1/requests/{id}?waitSeconds=60 until the status is final.
{
"id": "req_01j9x4m6v4c8k2t7q0r5s3w1zb",
"objectType": "request",
"createdAt": "2026-10-05T16:03:59.002Z",
"projectId": "proj_01j9...",
"endUserId": "eu_01j9...",
"connectionId": "conn_01j9...",
"operationId": "qbd.customers.create",
"method": "POST",
"path": "/v1/quickbooks-desktop/customers",
"mode": "async",
"idempotencyKeyPresent": true,
"previousRequestId": null,
"status": "succeeded",
"waitingReason": null,
"queuePosition": null,
"outcome": "applied",
"sentAt": "2026-10-05T16:04:02.517Z",
"completedAt": "2026-10-05T16:04:03.140Z",
"queueTtlExpiresAt": "2026-10-05T18:03:59.002Z",
"durationMs": 4138,
"timings": { "queuedMs": 3515, "quickbooksMs": 623, "totalMs": 4138 },
"quickbooks": { "qbxmlVersion": "16.0", "messageSetId": "Vd9bq3kQx0m2R7yA1cT5wE", "statusCode": 0, "statusSeverity": "Info" },
"warnings": [],
"recovered": false,
"timeline": [
{ "at": "2026-10-05T16:03:59.002Z", "status": "queued", "detail": "awaiting_check_in", "elapsedMs": 0 },
{ "at": "2026-10-05T16:04:02.517Z", "status": "sent", "detail": null, "elapsedMs": 3515 },
{ "at": "2026-10-05T16:04:03.140Z", "status": "succeeded", "detail": null, "elapsedMs": 4138 }
],
"diagnosis": null,
"error": null,
"result": { "id": "80000042-1730313843", "objectType": "qbd_customer", "name": "Northwind Traders" },
"resultExpired": false
}
Status Final Meaning
queued No Accepted and waiting for its turn or the next check-in
waiting_for_connection No Async only: the connection is offline or QuickBooks is unavailable; the request goes out when it recovers, or expires
sent No Handed to QuickBooks. It can no longer be canceled
succeeded Yes QuickBooks accepted it, possibly with warnings
failed Yes Definitive failure; error explains why
canceled Yes Canceled before it was sent, by you or by a sync deadline
outcome_unknown Yes, for you A write was sent and its result could not be confirmed. Verify before writing again. See Idempotency and safe retries

New statuses may appear; treat unknown ones as not final.

While a request waits, waitingReason says why and queuePosition says how many requests are ahead (1 means next).

waitingReason Meaning
awaiting_check_in Waiting for the Web Connector’s next check-in
behind_other_requests Other requests for this company file go first
opening_company_file QuickBooks is opening the file
quickbooks_starting QuickBooks is starting
connector_offline The computer or Web Connector is offline (async requests)
quickbooks_unavailable The Web Connector checks in but QuickBooks cannot open the file; error previews the reason
quickbooks_not_responding A Web Connector session is open but QuickBooks has not answered it for 20 seconds
write_recovery_pending An earlier write’s outcome is unknown; later writes wait until that session ends, reads continue

Each timeline step has elapsedMs since the request was created. Besides status changes, the timeline records waiting (the waiting reason changed), diagnosed, and steps for cursors and write holds. timings splits the duration into time in the queue (queuedMs) and time in QuickBooks (quickbooksMs).

While a request waits or runs long, and after it timed out or expired, diagnosis ranks the probable causes from what we observed of the Web Connector and QuickBooks, with fixes for you and your customer. See Request diagnosis.

outcome tells you whether a write changed the company file: applied, not_applied, pending, unknown, or not_applicable for reads. Errors carry the same field. It is the field to check before retrying a write.

QuickBooks sometimes accepts a request and adds a warning, for example when it adjusts a value. We return the result with a Daapi-Warnings header that counts them, and record each warning (code, statusCode, message, path) in the request’s warnings array. The same array lists values the API had to read leniently from a damaged company file (QBD_VALUE_UNREADABLE, QBD_MARKUP_REPAIRED, with statusCode: null and the path of the value in result); see Damaged and unusual data.

Request metadata, timelines and errors stay readable for 30 days. Request and response bodies stay for 15 days, after which result is null and resultExpired is true. A project can turn body capture off in the dashboard; bodies are then kept only until 24 hours after the request completes. See Security and data retention.

GET /v1/requests lists a project’s requests newest first, filtered by endUserId, status (repeatable), operationId, createdAfter and createdBefore. Items are request summaries with an errorCode instead of the full error, timeline and result; read one request for the details. The list follows each status change within seconds.

POST /v1/requests/{id}/cancel cancels a request that is still queued or waiting_for_connection. It becomes canceled with REQUEST_CANCELED, and a sync caller still waiting on it receives that error. Canceling an already canceled request returns it unchanged. Any other status returns 409 REQUEST_NOT_CANCELABLE with details.status, because a sent request may already be changing the company file.

QBD_QUICKBOOKS_NOT_RESPONDING, REQUEST_TIMEOUT_NOT_SENT, QBD_REQUEST_TIMEOUT, REQUEST_EXPIRED, REQUEST_CANCELED, REQUEST_NOT_CANCELABLE, QBD_READ_INTERRUPTED, INTEGRATION_CONNECTION_NOT_ACTIVE.