Skip to content
Desktop Accounting API

Error handling

Integrations with QuickBooks Desktop fail in ordinary ways: the customer’s computer is off, QuickBooks has a dialog open, a name already exists. Every error from this API tells you which kind of failure it is, whether retrying can help, whether a write reached QuickBooks, and what to tell your customer. The full list of codes is in the error code reference.

Every error response has this body, with the HTTP status in httpStatusCode as well:

{
"error": {
"type": "INTEGRATION_ERROR",
"code": "QBD_DUPLICATE_NAME",
"message": "QuickBooks returned status 3100: The name \"Northwind Traders\" of the list element is already in use.",
"userFacingMessage": "A record with this name already exists in QuickBooks Desktop.",
"httpStatusCode": 409,
"integrationCode": "3100",
"requestId": "req_01j9x4m6v4c8k2t7q0r5s3w1zb",
"cause": "QuickBooks names must be unique within a list, and across customers, vendors, employees and other names.",
"fixes": [{ "actor": "developer", "action": "Use a different name, or look up and reuse the existing object." }],
"docsUrl": "https://www.desktopaccountingapi.com/docs/errors/#qbd_duplicate_name",
"retryable": false,
"outcome": "not_applied",
"param": "name",
"details": { "requestId": "req_01j9x4m6v4c8k2t7q0r5s3w1zb", "qbxmlStatusCode": 3100, "qbxmlStatusMessage": "The name \"Northwind Traders\" of the list element is already in use." }
}
}
Field Meaning
type One of nine categories below. Route on it.
code A stable code from the catalog. A code’s meaning never changes.
message For you: specific, may contain IDs and field paths, never secrets. Log it.
userFacingMessage For your customer: plain language, always present. Authentication, billing and internal problems are masked to a neutral sentence.
httpStatusCode The HTTP status of the response.
integrationCode The native code when QuickBooks or the Web Connector produced one: a qbXML status code ("3100"), a COM HRESULT ("0x80040414") or a Web Connector code ("QBWC1039").
requestId The request ID (req_...), also in the Daapi-Request-Id header.
cause, fixes Why it happened, and what to do. Each fix names who acts: developer, end_user or support.
docsUrl The section of the error reference for this code.
retryable Whether repeating the same request, unchanged, can succeed. Also sent as the Daapi-Should-Retry header. The error reference gives each code a fuller retry rule.
outcome Whether a write changed the company file: applied, not_applied, pending, unknown, or not_applicable for reads.
param The request field at fault, as a path such as lines[2].amount, when known.
details Extra data for some codes, such as pagesServed on CURSOR_EXPIRED, minimumQbxmlVersion on version errors, or a ranked diagnosis on timeouts and QBD_QUICKBOOKS_NOT_RESPONDING. The error reference lists the keys per code.
Type What happened How to handle it
INVALID_REQUEST_ERROR Your request is malformed or breaks a rule. Nothing reached QuickBooks. Fix the code. Do not retry unchanged.
AUTHENTICATION_ERROR Missing, invalid or revoked key. Check configuration and alert yourself.
PERMISSION_ERROR Valid key, action not allowed (wrong project, disabled connection). Check the project and connection.
BILLING_ERROR Production data requests are blocked by billing. Fix billing in the dashboard. See Billing.
RATE_LIMIT_ERROR Too many requests. Wait for Retry-After and retry. See Rate limits.
INTEGRATION_CONNECTION_ERROR Something on the customer’s computer: offline, QuickBooks closed or busy, a dialog open, the wrong file. Show userFacingMessage, retry later if retryable. Log as a warning, not an incident.
INTEGRATION_ERROR QuickBooks received the request and rejected it, for example a duplicate name or stale revision. Usually a data problem to fix in code. integrationCode holds the qbXML status.
OUTCOME_UNKNOWN_ERROR A write was sent and its result could not be confirmed. Never resend it. See uncertain writes.
INTERNAL_ERROR A problem on our side. Retry reads. For writes, check outcome first.

New types and codes can appear. Handle unknown values as a generic failure and keep userFacingMessage as the message.

retryable (and the Daapi-Should-Retry header) answers one question: can the identical request succeed later without anyone changing it? Use it together with outcome:

retryable outcome Do this
true not_applied Retry with backoff, honoring Retry-After. Reuse the same Idempotency-Key for writes.
false not_applied Do not retry. Fix the request, or ask the customer to fix their setup.
any pending Do not resend. The request is still running; read it with GET /v1/requests/{id}?waitSeconds=60.
any unknown Do not resend. Verify in QuickBooks first.
any applied The change happened. Do not resend.

The SDKs follow this table for you: they retry network failures, 429 and 5xx responses whose Daapi-Should-Retry is true, with exponential backoff from 0.5 to 8 seconds, up to two retries by default, and never when outcome is pending or unknown.

Each SDK raises one error class per type, with every field available as a property.

import {
DesktopAccountingApi,
ApiError,
IntegrationConnectionError,
OutcomeUnknownError,
} from "@desktopaccountingapi/quickbooks-desktop";
const qb = new DesktopAccountingApi().forEndUser("eu_01j9...");
try {
await qb.qbd.customers.create({ name: "Northwind Traders" });
} catch (err) {
if (err instanceof IntegrationConnectionError) {
console.warn(err.code, err.requestId);
// show err.userFacingMessage to your customer
} else if (err instanceof OutcomeUnknownError) {
// do not retry: look the customer up by name or externalId first
} else if (err instanceof ApiError && err.code === "QBD_DUPLICATE_NAME") {
// reuse the existing customer
} else {
throw err;
}
}
Type TypeScript Python C# Java
Base class ApiError APIError ApiException ApiException
INVALID_REQUEST_ERROR InvalidRequestError InvalidRequestError InvalidRequestException InvalidRequestException
AUTHENTICATION_ERROR AuthenticationError AuthenticationError AuthenticationException AuthenticationException
PERMISSION_ERROR PermissionError PermissionDeniedError PermissionException PermissionException
BILLING_ERROR BillingError BillingError BillingException BillingException
RATE_LIMIT_ERROR RateLimitError RateLimitError RateLimitException RateLimitException
INTEGRATION_CONNECTION_ERROR IntegrationConnectionError IntegrationConnectionError IntegrationConnectionException IntegrationConnectionException
INTEGRATION_ERROR IntegrationError IntegrationError IntegrationException IntegrationException
OUTCOME_UNKNOWN_ERROR OutcomeUnknownError OutcomeUnknownError OutcomeUnknownException OutcomeUnknownException
INTERNAL_ERROR InternalError InternalError InternalException InternalException
CURSOR_EXPIRED CursorExpiredError CursorExpiredError CursorExpiredException CursorExpiredException
No response at all ApiConnectionError APIConnectionError ApiConnectionException ApiConnectionException
  • Branch on type first, then on the few code values you handle specially. Treat everything else in a type the same way.
  • Show userFacingMessage, not message, to customers. It is safe by design, and for connection errors it tells them exactly what to do on their computer. Link the help center next to it.
  • Alert on your own failures, not your customers’. AUTHENTICATION_ERROR, INVALID_REQUEST_ERROR, INTERNAL_ERROR and a rise in INTEGRATION_ERROR deserve attention. INTEGRATION_CONNECTION_ERROR is usually a customer’s PC being off.
  • Store requestId with failures. The dashboard request log opens it directly, with the timeline and native QuickBooks status, and support can find it immediately.
  • Prefer user-started syncs. When a sync runs because a person clicked a button, a connection error becomes a message they can act on. For scheduled syncs, record the last error per customer and show it in your UI.

When QuickBooks rejects a request, integrationCode holds its qbXML status code and details.qbxmlStatusMessage holds QuickBooks’ own text. Common ones map to dedicated codes:

qbXML status Code
3100 QBD_DUPLICATE_NAME
3120, 3140 QBD_OBJECT_NOT_FOUND for the ID in the path, QBD_REFERENCE_NOT_FOUND for a referenced ID (with param)
3175, 3176 QBD_OBJECT_IN_USE (someone has the record open in QuickBooks; for a deletion, other records may still use it)
3200 QBD_REVISION_NUMBER_STALE
3250 QBD_FEATURE_NOT_ENABLED
3260 QBD_INSUFFICIENT_PERMISSION (the QuickBooks user’s role)
3261 QBD_INSUFFICIENT_PERMISSION (the app may not access personal data, for example payroll reports)
Any other error status QBD_REQUEST_ERROR

Connection-level failures carry the COM HRESULT that QuickBooks returned, such as 0x80040414 for an open dialog or 0x8004040A for the wrong company file. The error reference lists every mapped code.