Appearance
Error codes
A developer hitting a TenkeyBridge error should never wonder what happened. Every fault carries three layers of help:
- The QBO-compatible
Fault— the exact shape the QuickBooks Online API uses, so existing QBO SDKs and error handlers keep working unchanged. Branch oncode. - A
tkbblock — TenkeyBridge's enrichment: likely causes, concrete fixes, and a docsUrl deep-linking to that code's section on this page. It sits outsideFault, in a top-level field QBO clients ignore. - A docs link in
Detail— so even if your SDK only surfacesMessage/Detail, the trail to the full story is still in front of you.
The fault envelope
jsonc
{
"Fault": {
"Error": [{
"code": "UNSUPPORTED_BY_DESKTOP",
"Message": "Unsupported by QuickBooks Desktop",
"Detail": "Sparse update of Line is not supported yet for Bill; line-level updates are currently supported on sales forms (Invoice, Estimate, SalesReceipt, CreditMemo) only. Re-create the transaction or update header fields only. See https://docs.tenkeybridge.com/reference/error-codes.html#unsupported_by_desktop",
"element": "Bill.Line"
}],
"type": "ValidationFault"
},
"time": "2026-07-24T00:00:00.000Z",
"tkb": {
"code": "UNSUPPORTED_BY_DESKTOP",
"causes": [
"The field, line type, item type, or operation you sent exists in QuickBooks Online but has no equivalent in QuickBooks Desktop's qbXML API — or the whole entity is a documented Desktop gap."
],
"fixes": [
"Remove or replace the unsupported value; the fault's element and Detail name exactly what triggered it.",
"Check the entity's section on https://docs.tenkeybridge.com/compatibility/ for the full list of supported fields and operations."
],
"docsUrl": "https://docs.tenkeybridge.com/reference/error-codes.html#unsupported_by_desktop"
}
}Fault.Erroris always an array (currently always length 1);codeis the value to branch on;element(when present) names the field that triggered the fault.Fault.typeisValidationFaultfor anything you can fix by changing the request or the company file,SystemFaultfor TenkeyBridge-side failures (HTTP 5xx).tkbis additive and versioned with the codes themselves (ERROR_CODES_VERSION = "2026-07"). Never required for correct handling — branch oncode; readtkbwhen a human needs to know what to do next.
The string codes below are TenkeyBridge's own, part of the public API surface — their meaning won't change under you between versions. Numeric codes carry the same meaning they have in the QuickBooks Online API.
Translation codes
Raised when a request can't be translated honestly to QuickBooks Desktop. These are almost always fixable by changing the request.
UNSUPPORTED_BY_DESKTOP
HTTP 422 · You sent a field, line type, item type, operation, or whole entity that has no QuickBooks Desktop equivalent.
Causes
- The field or operation exists in QuickBooks Online but qbXML (Desktop's API) has no way to express it — a permanent platform gap, not a missing TenkeyBridge feature.
- The entity itself is a documented gap (Attachable, Budget, …) or not yet shipped in TenkeyBridge. Entity-level responses link straight to that entity's section on the compatibility page.
Fixes
- Remove or replace the value — the fault's
elementandDetailname exactly what triggered it. - Check the entity's section on the compatibility page for the full list of supported fields and operations, and the closest supported alternative.
- For Desktop-backed realms, branch on this code and degrade gracefully (skip the feature) rather than retrying — the same request will fail the same way every time.
jsonc
{
"Fault": {
"Error": [{
"code": "UNSUPPORTED_BY_DESKTOP",
"Message": "Unsupported entity",
"Detail": "Item create/update lands in a later TenkeyBridge release. Pull items with read/query for now. See https://docs.tenkeybridge.com/reference/error-codes.html#unsupported_by_desktop",
"element": "Item"
}],
"type": "ValidationFault"
}
}UNSUPPORTED_QUERY
HTTP 400/422 · Your query is valid QBO syntax, but TenkeyBridge can't answer it reliably.
Causes
- A gateway-side filter,
ORDERBYorCOUNT(*)that would have to scan more than 5,000 records — 1,000 for transactions fetched with line items (TenkeyBridge fails loudly rather than return a possibly-incomplete answer). TheDetailnames the clause. STARTPOSITIONpaging past what Desktop can serve for that query shape.- A QBO property Desktop has no equivalent for (the
Detailnames it). - A clause the entity doesn't take:
CompanyInfo,PreferencesandBudgetaccept only a bareSELECT *(andIdon Budget).
Fixes
- Narrow the query with filters QuickBooks applies itself — a
TxnDateorMetaData.LastUpdatedTimerange,Active,Id, aCustomerRef/VendorRef, a name prefix — so the scan stays under the cap. See Query support for which conditions are pushed into QuickBooks and which are applied gateway-side.
UNMAPPED_FIELD
HTTP 422 · The payload contains a field TenkeyBridge doesn't recognize for this entity.
Causes
- A typo in a field name, a QBO minor-version field, or a field that belongs to a different entity. Distinct from
UNSUPPORTED_BY_DESKTOP: unmapped means "not a known field at all", unsupported means "known, but Desktop can't do it".
Fixes
- Drop the field or fix the spelling; the entity's field table on the compatibility page lists every accepted field.
UNMAPPED_ACCOUNT_TYPE
HTTP 422 · The AccountType (or AccountSubType) value has no QuickBooks Desktop account-type equivalent.
Fixes
- Use one of the Desktop-mappable account types listed in the Account section of the compatibility page; the fault's
Detailnames the closest supported type when there is one.
MISSING_REQUIRED_DESKTOP_ITEM
HTTP 422 · You referenced something QuickBooks Desktop models as an item in the company file, but the request doesn't point at one that exists.
Causes
- Most commonly a bare-percentage or amount-off discount with no
ItemRef— Desktop discounts are discount items; there is no "anonymous discount".
Fixes
- Create the item in the Desktop company file, then reference it (e.g.
DiscountLineDetail.ItemRef, byvalue= ListID orname= the item's full name). TenkeyBridge does not choose a default discount item for you.
Warnings
Non-fatal conditions come back on a successful response as an X-TKB-Warning header (printable ASCII, capped at 500 characters, several warnings joined with ; ). They are never sent on error responses. See Warnings.
QuickBooks warning <code>: <message>when QuickBooks Desktop performed the request but answered with a warning-severity status for part of it, for exampleQuickBooks warning 530: The field "Name" is not supported by this implementation.TxnTaxDetail.TotalTax ignored; QuickBooks Desktop computed <amount>on Invoice, SalesReceipt, Estimate and CreditMemo create/update when you sent aTotalTax(without aTxnTaxCodeRef) that differs from the tax Desktop computed. Not emitted for/batchitems.
Gateway codes
Raised by the TenkeyBridge gateway before or after translation — routing, auth, and the connection to the agent running next to QuickBooks Desktop.
NOT_FOUND
HTTP 404 · The URL doesn't match any TenkeyBridge route, or the entity segment isn't a known QuickBooks entity name at all (typo / unknown string). Known-but-unsupported entities return UNSUPPORTED_BY_DESKTOP instead.
Fixes
- Check the path shape (
/v3/company/{realmId}/{entity}) and the entity spelling against the entity matrix.
AUTHENTICATION_FAILED
HTTP 401 · The Authorization header is missing, isn't a Bearer token, or the access token is invalid or expired.
Causes
- Access tokens live 60 minutes — the most common cause is simply an expired token.
Fixes
- Send
Authorization: Bearer <access_token>. - When the access token expires, exchange your refresh token at
/oauth2/v1/tokens(grant_type=refresh_token) for a fresh pair — and store the new refresh token; refresh tokens rotate on every use.
AUTHORIZATION_FAILED
HTTP 403 · The access token is valid but was issued for a different realm than the one in the URL path.
Fixes
- Use the
realmIdreturned in your OAuth callback together with the tokens minted for it — realm and token travel as a pair. - If you meant to talk to a different company file, run the connect flow again for that realm.
RATE_LIMITED
HTTP 429 · This company (realm) sent more REST requests than the per-minute limit allows.
Every response on this surface — limited or not — carries three headers so you can see your budget before you hit it:
| Header | Meaning |
|---|---|
RateLimit-Limit | Requests allowed per minute for this realm. |
RateLimit-Remaining | Requests left in the current window. |
RateLimit-Reset | Seconds until the window resets. |
A 429 additionally carries:
| Header | Meaning |
|---|---|
Retry-After | Seconds to wait before retrying (an integer, always ≥ 1). |
Causes
- This company (realm) sent more REST requests than the per-minute limit allows.
Fixes
- Wait for the number of seconds in
Retry-After, then retry. - Watch
RateLimit-Remainingon ordinary responses and back off before it reaches 0, rather than polling at the edge of the limit. - Batch or page requests instead of polling in a tight loop; use CDC for change-tracking instead of repeated full queries.
The OAuth token/authorize endpoints and the portal sign-in endpoints enforce their own, separate per-IP limits — see OAuth errors for the slow_down shape returned there. Both carry the same four headers.
QUERY_PARSER_ERROR
HTTP 400 · The query parameter is missing or empty.
Fixes
- Pass a QBO-SQL statement in the
queryparameter, URL-encoded:GET /v3/company/{realmId}/query?query=SELECT%20*%20FROM%20Customer.
BAD_REQUEST
HTTP 400 · The request doesn't form a valid operation.
Causes
- A non-JSON request body, an unsupported
?operation=value, or an update/delete without the record'sId.
Fixes
- The
Detailnames the exact problem; correct the request shape and resend. Updates and deletes need a JSON body carrying the entity'sId(andSyncToken).
AGENT_OFFLINE
HTTP 503 · Nothing is serving this realm right now — no agent connected and no Web Connector polling. The gateway raises this only before sending a request; a request lost after it was sent is a 504 AGENT_TIMEOUT.
Causes
- The Windows machine hosting QuickBooks Desktop is off or asleep, the agent isn't running, or its network path to the gateway is down.
- Over Web Connector: Web Connector isn't running on the QuickBooks machine, Auto-Run is off for this entry, or the hosted-desktop session disconnected.
Fixes
- Start the agent on the machine hosting QuickBooks Desktop and retry — requests succeed as soon as it reconnects.
- Over Web Connector: open Web Connector, tick Auto-Run on the TenkeyBridge entry, and wait one poll (~10 s); see the Web Connector guide.
- Nothing is queued: this request was not executed, so it's always safe to retry.
- If the realm polls unattended (e.g. overnight), treat 503 as "come back later", not as a failure.
AGENT_TIMEOUT
HTTP 504 · The request was sent, but its answer never came back — QuickBooks didn't answer inside the request budget, or the connection was lost first. The code is the same for both transports; the Message says which one waited — "Agent for realm …" (60 s budget) or "Web Connector for realm …" (4-minute budget, because Web Connector may be cold-launching QuickBooks under the unattended grant).
Causes
- A modal dialog open in QuickBooks on the host machine (the #1 culprit), a very large request, or the company file busy with another operation.
- Over Web Connector: QuickBooks was closed and a hosted desktop took longer than the 4-minute budget to launch it (see the Web Connector guide).
- The connection to the agent dropped, or the gateway restarted (usually a deploy), after the request was sent — the
Messagesays the connection was lost or the gateway restarted.
Fixes
- Dismiss any open dialog in QuickBooks on the host machine, then retry.
- Break very large queries into pages.
- ⚠️ The request may still have applied after the gateway gave up — re-query before retrying a write to avoid duplicates, or send the write with a
requestidso the retry is safe (Safe retries).
QB_NOT_OPEN
HTTP 503 · The agent is connected, but QuickBooks isn't open in the Windows session the agent runs in, so the request was not executed. Raised by the edge agent (never by Web Connector) and only before anything is sent to QuickBooks — always safe to retry, writes included. If a Web Connector is also live for the realm, the gateway retries the request there automatically before returning this.
Causes
- QuickBooks was closed, or the hosted-desktop (for example Rightworks) session was disconnected and reconnected without it.
Fixes
- Open QuickBooks on the pinned company file in the same Windows session the agent runs in, then retry.
- The agent can be configured to fail this way instead of launching QuickBooks itself (
RequireQuickBooksRunning); see the Rightworks guide. - Nothing is queued: treat it like
AGENT_OFFLINE— come back later.
VOID_APPLIED_READBACK_FAILED
HTTP 502 (per-item fault slot in a batch) · The void was applied in QuickBooks, but reading the voided record back failed, so the outcome of the read is unknown.
Causes
- The agent went offline or timed out between the
TxnVoidRqand the follow-up read. - The read-back response could not be translated.
Fixes
- Do not retry the void — it already took effect, and a retry fails with a stale
SyncToken(5010).GET /{entity}/{Id}to see the voided record.
CUSTOM_FIELD_UNKNOWN
HTTP 400 · A CustomField in the request names a field that is not defined in this QuickBooks company file, or that is defined but not assigned to this record type. Checked before anything is written, so nothing was saved.
Causes
- A misspelled
Name, or a custom field that only exists in QuickBooks Online / another company file. - A field defined for Customers being set on an Invoice (Desktop custom fields are assigned per record type).
Fixes
- Define the custom field in QuickBooks Desktop (Lists > Customer & Vendor Profile Lists > Custom Fields, or the Sales form's Additional Info), tick the record type, and resend. Matching is case-insensitive.
DefinitionIdalone cannot identify a Desktop field — send theName.
CUSTOM_FIELD_WRITE_FAILED
HTTP 502 (per-item fault slot in a batch) · The record was saved in QuickBooks, but writing one or more of its custom-field values failed afterwards. The fault names the record's Id, the fields that were applied and the ones that failed.
Causes
- QuickBooks rejected a value, the agent went offline mid-request, or the field definition changed between the up-front check and the write.
Fixes
- Do not retry the whole request: a create would duplicate the record.
GETthe record and send an update carrying only the failedCustomFieldentries.
CUSTOM_FIELD_READBACK_FAILED
HTTP 502 (per-item fault slot in a batch) · The record and all of its custom-field values were written in QuickBooks, but reading it back for the response failed.
Causes
- The agent went offline or timed out after the writes, or the read-back could not be translated.
Fixes
- Do not retry — everything was applied.
GET /{entity}/{Id}to see the record.
PAYMENT_OUTCOME_UNKNOWN
HTTP 502 · QuickBooks answered a payment request with success but returned no payment record, so the outcome is unknown. Credits named in the request may have been applied.
Causes
- A credit-only application (credit memos with a zero or omitted
TotalAmt): Desktop applies the credit and creates no payment. TenkeyBridge refuses that request up front with a 422, so this 502 is a defensive backstop.
Fixes
- Do not retry.
GETthe invoice and credit memo to see whether the credit was applied. - Apply credit memos together with a cash amount, or apply them in QuickBooks.
REQUESTID_INVALID
HTTP 400 · The requestid query parameter on a write is malformed. See Safe retries.
Causes
- Empty, longer than 50 characters, or containing spaces, control characters or non-ASCII characters.
- On
/batch: longer than 36 characters, or an itembIdlonger than 10 characters (QuickBooks Online's own limits).
Fixes
- Send a unique token of 1-50 printable ASCII characters without spaces; a UUID works.
REQUESTID_BODY_MISMATCH
HTTP 422 · This requestid was already used for a different request - a different body, entity or operation. Nothing was executed.
Causes
- A
requestidreused for a new write, or a retry whose payload changed between attempts.
Fixes
- Use a new
requestidfor every new write; reuse one only to retry the exact same request.
REQUEST_IN_FLIGHT
HTTP 409 (with Retry-After) · A request with this requestid is still being processed. Nothing new was executed.
Causes
- You retried while the original call was still running in QuickBooks.
Fixes
- Wait
Retry-Afterseconds and resend the same request with the samerequestid; you will get the original result.
REQUEST_OUTCOME_UNKNOWN
HTTP 502 · The original request with this requestid was lost after it reached QuickBooks (a 504 AGENT_TIMEOUT or a dropped connection) and TenkeyBridge could not confirm whether it applied. The write is never re-sent.
Causes
- The answer never came back, and the record could not be found (or, for updates, cannot be proven to be ours) on a re-read.
Fixes
- Look the record up in QuickBooks (query by
DocNumberorId) and decide. - Retrying with the same
requestidre-checks for free and returns the result as soon as it can be confirmed; if a late-running request applies after all, the next retry reports it. - See Safe retries.
AGENT_EXECUTION_ERROR
HTTP 502 · The request reached QuickBooks but failed at the QuickBooks/COM layer. The raw Windows-side error stays in the gateway logs (and the agent's, when one is in use), since it can contain machine-local detail.
Causes
- QuickBooks isn't running, or no company file is open.
- A QuickBooks login or authorization dialog is blocking access.
- The agent and
QBW.exerun at different Windows integrity levels — they must match (run both non-elevated).
Fixes
- On the host machine: open QuickBooks with the company file, run both QuickBooks and the agent non-elevated, and check the agent log for the exact underlying error.
- Over Web Connector: the error is recorded on the connector's row in the portal (the "last error" detail);
QB_COMPANY_FILE_UNAVAILABLEthere means the wrong company file is open — see Which company file.
INTERNAL_ERROR
HTTP 500 · An unexpected error inside the TenkeyBridge gateway — not your request and not QuickBooks.
Fixes
- Retry once; if it persists, report it along with the response's
timefield so it can be correlated with the gateway logs.
SUBSCRIPTION_REQUIRED
HTTP 402 · This company's organization has no active TenkeyBridge subscription.
Causes
- The organization's trial ended, or more than one realm is connected on the trial plan — trial accounts are limited to one realm.
- A production subscription's payment lapsed and stayed unpaid past the 7-day grace period.
Fixes
- Subscribe or manage billing for the organization in the TenkeyBridge portal — see the billing guide.
- On a trial, each organization may connect at most one realm — upgrade to a paid plan to connect more.
SANDBOX_UNSUPPORTED
HTTP 400 · The sandbox doesn't emulate this request.
Causes
- Reports and budgets (served from static captures in a later release), group item lines, or a query filter the sandbox doesn't implement. The fault's
Detailnames the request.
Fixes
- Test that call against a real QuickBooks company file over the Web Connector.
- Everything else keeps working in the sandbox; only this request is refused.
SANDBOX_DAILY_LIMIT
HTTP 429 · This sandbox used its REST calls for today (UTC).
Causes
- More calls than the sandbox daily limit (2,000 by default) since 00:00 UTC.
Fixes
- Wait for the reset at 00:00 UTC;
Retry-Aftergives the seconds remaining. - In CI, reset the sandbox once per run and page with
MAXRESULTSinstead of polling.
SANDBOX_RECORD_LIMIT
HTTP 400 · The sandbox holds its maximum number of records.
Causes
- A create would exceed the record limit (10,000 by default). Deactivated list records still count; deleted transactions don't.
Fixes
- Delete transactions you no longer need, or reset the sandbox.
CDC_INVALID_ENTITIES
HTTP 400 · The entities parameter is missing, empty, or not a comma-separated list of QBO entity names.
Causes
- No
entitiesparameter, an empty one, or a value that isn't a comma-separated list (e.g.entities=Invoice,Customer,Bill).
Fixes
- Pass
entitiesas a comma-separated list of entity names. Unsupported names don't fail the request — they come back as per-entityFaultslots — but the parameter itself must be present and non-empty.
CDC_INVALID_CHANGED_SINCE
HTTP 400 · changedSince is missing, unparseable, or outside the 30-day CDC look-back window.
Causes
changedSinceisn't a parseable ISO 8601 timestamp orYYYY-MM-DDdate.changedSinceis older than the 30-day CDC look-back window — the same limit QuickBooks Online enforces; it also bounds worst-case Desktop query cost.
Fixes
- Pass
changedSinceas an ISO 8601 timestamp (2026-07-01T00:00:00Z) or bare date (2026-07-01) within the last 30 days. - Syncing older data? Do a full walk with
/queryand aMetaData.LastUpdatedTimefilter instead — CDC is for incremental polling.
CDC_OVERFLOW
HTTP 400 · More than 1,000 objects changed for one entity in the requested window.
Causes
- A CDC slot never silently truncates, so once an entity crosses 1,000 changed objects in the window it returns this fault instead of a partial array.
Fixes
- Shorten the
changedSincewindow and poll more frequently. - Or walk this entity with
/queryusing aMetaData.LastUpdatedTimefilter plusSTARTPOSITION/MAXRESULTSpagination — that path has no object cap.
BATCH_INVALID_REQUEST
HTTP 400 · The batch envelope or one of its items is structurally malformed.
Causes
BatchItemRequestis missing, empty, or not an array; a missing or duplicatebId; an item that isn't exactly oneQueryor one entity payload; a missing or unknown operation; or an operation/Idcombination that contradicts itself (create with anId, update/delete without one).
Fixes
- Nothing executed — a malformed envelope never half-runs. The fault
Detailnames the offending item bybIdor index; fix that item's shape and resend the whole batch.
BATCH_TOO_MANY_ITEMS
HTTP 400 · The batch carries more than 30 items.
Causes
- More than 30 items in one batch — the same per-request cap QuickBooks Online enforces.
Fixes
- Split the work into multiple batch calls of at most 30 items each. Items execute sequentially either way, so splitting costs no extra Desktop round trips.
BATCH_UNSUPPORTED_OPTION
HTTP 200 (per-item fault slot — the batch request itself is not a 400) · The item carries an unsupported optionsData value.
Causes
- The item carries an
optionsDatavalue other than"void", or"void"on a create/delete item — onlyoptionsData: "void"on an update item (QBO's spelling) is wired.
Fixes
- Drop
optionsDatafrom the item, or for a void sendoperation: "update"withoptionsData: "void"and the record'sId+SyncToken. Only this item faulted — the rest of the batch still ran.
REPORT_UNKNOWN
HTTP 422 · The report name in the URL is not one TenkeyBridge serves from Desktop.
Causes
- The report name is not one of the 20 reports TenkeyBridge serves from QuickBooks Desktop. QuickBooks Online's report catalogue is larger;
CashFlowin particular does not exist in QuickBooks Desktop's SDK (qbXML has no cash-flow report), and class/department/tax families are not shipped.
Fixes
- Use one of the names in the fault detail (
ProfitAndLoss,BalanceSheet,TrialBalance,GeneralLedger,TransactionList, the aged and balance reports, ...). Names match case-insensitively. - Check the compatibility page for the current report coverage before adding a new report call.
REPORT_UNSUPPORTED_OPTION
HTTP 422 · The request carries a report parameter Desktop cannot honour.
Causes
- The request carries a QuickBooks Online report parameter that Desktop's report engine cannot honour — column selection, a filter or column split qbXML has no twin for (
department,Employees/ProductsAndServicescolumns), an aging knob that lives in company-file preferences rather than the request, oraccounting_methodon a report Desktop refuses aReportBasisfor.
Fixes
- Drop the parameter and read the standard Desktop layout; the fault's
elementnames exactly which one failed. - For aging buckets, change them in QuickBooks under Edit > Preferences > Reports & Graphs — Desktop returns whatever the company file is configured with, as the report's columns.
- For a filter or column split Desktop cannot express, fetch the report and narrow it client-side. Supported filters are
customer,vendor,itemandclass(Ids); supported column splits areTotal,Month,Week,Days,Quarter,Year,Customers,VendorsandClasseson the period summary reports.
REPORT_INVALID_DATE
HTTP 400 · A report date or date macro was not usable.
Causes
- A report date was not a real calendar date in
YYYY-MM-DDform,start_dateandend_datewere not supplied together,start_datefell afterend_date, ordate_macrowas not one of QuickBooks Online's date macros.
Fixes
- Send
start_dateandend_datetogether asYYYY-MM-DD, or senddate_macroalone — not a partial pair. - For the aging reports use
report_date(a single as-of date), notstart_date/end_date. - Omit the dates entirely to get the fiscal year-to-date window, which is what the same call returns from QuickBooks Online.
Numeric codes
Numeric codes carry the same meaning they have in the QuickBooks Online API, so existing QBO error-handling logic keeps working unchanged. They come from three places: mapped from QuickBooks Desktop status codes when Desktop itself rejects the request (610, 5010, 6240, 2500, and 2020 from Desktop's 3070); raised by TenkeyBridge's own validation before the request ever reaches Desktop (2010, 2020, 2050, and 4000 for a query QBO's grammar rejects); and 500 for an internal TenkeyBridge failure.
610 — Object not found
HTTP 400 · No record with the given Id exists in the company file.
Causes
- The record was deleted in QuickBooks, or the
Idbelongs to a different realm. - Desktop Ids differ from QBO Ids for the same logical record — an Id carried over from a QBO integration will never match.
Fixes
- Re-query for the record to get its current Id in this realm.
5010 — Stale object
HTTP 400 · Optimistic-concurrency conflict: the SyncToken you sent is stale (Desktop's EditSequence).
Causes
- A user or another integration modified the record in QuickBooks after you read it.
Fixes
GETthe record again, take the freshSyncToken, and re-apply your change.
jsonc
{
"Fault": {
"Error": [{
"code": "5010",
"Message": "Stale Object Error",
"Detail": "QuickBooks Desktop: The provided edit sequence is out-of-date. See https://docs.tenkeybridge.com/reference/error-codes.html#5010"
}],
"type": "ValidationFault"
}
}6240 — Duplicate name exists
HTTP 400 · A list record with this name already exists.
Causes
- Desktop names (
Customer,Vendor,Item, …) must be unique per list — including inactive records, which is the case that usually surprises QBO-first integrations.
Fixes
- Use the existing record, pick a different name, or rename/reactivate the conflicting record in QuickBooks.
2500 — Invalid reference
HTTP 400 · A *Ref you sent (CustomerRef, ItemRef, AccountRef, …) points at a record that doesn't exist in the company file.
Fixes
- Query for the referenced record first and use its current Id; create it if it doesn't exist yet.
2010 — Invalid field value
HTTP 422 · A field value fails validation — wrong type, an unparseable date or number, or a value outside what Desktop accepts.
Fixes
- The
elementandDetailname the field; correct the value and resend.
4000 — Query parse / validation error
HTTP 400 · QBO's own code for a query its grammar rejects. The Message starts with QueryParserError: (syntax) or QueryValidationError: (a property or value the entity doesn't accept), exactly as QBO words them.
Causes
- Invalid syntax: a missing
FROM,OR(the query language has none — join conditions withAND), an unquoted date or string, an unterminated string literal, parentheses around conditions,NOT LIKE, a badSTARTPOSITION/MAXRESULTS. - A property the entity doesn't have (
property Foo not found in Customer), an operator a property doesn't take (LIKEon a number), or a literal of the wrong type (TxnDate >= 'yesterday').
Fixes
- The
Detailnames the problem; correct the clause and resend.
2020 — Required parameter missing
HTTP 400/422 · A field the operation requires is missing — either one QBO requires, or one QuickBooks Desktop additionally requires (the Detail says which).
Fixes
- Add the named field and resend. Desktop-only requirements are also flagged per entity on the compatibility page.
2050 — String length out of range
HTTP 400 · A string field is longer than QuickBooks Desktop allows. Raised by TenkeyBridge's own validation before the request reaches Desktop. Today this covers DocNumber (Desktop's RefNumber), counted in characters (Unicode code points):
- 11 characters on Invoice, SalesReceipt, Estimate, CreditMemo, RefundReceipt, JournalEntry, PurchaseOrder, Purchase, and BillPayment.
- 20 characters on Bill and VendorCredit.
It also covers Payment's PaymentRefNum, which maps to Desktop's RefNumber too and is limited to 20 characters. The element names the field (for example Invoice.DocNumber) and the Detail states the limit.
Causes
- A
DocNumberlonger than the Desktop reference-number limit for that transaction type.
Fixes
- Shorten the value and resend. QuickBooks Online allows longer document numbers than Desktop, so integrations moving from QBO should cap or truncate
DocNumberup front.
500 — System failure
HTTP 500, SystemFault · TenkeyBridge hit an internal integrity error translating Desktop's response — for example a returned record missing its ListID or EditSequence. This is a TenkeyBridge bug, not a problem with your request.
Fixes
- Retry once; if it persists, report it with the response's
timefield.
Desktop status codes
Any QuickBooks Desktop status code without a QBO mapping passes through untouched as the fault's code (message Business Validation Error), so no error is ever swallowed — and the raw QuickBooks message is always preserved in Detail, prefixed QuickBooks Desktop:. For the notoriously cryptic common ones, the tkb block explains what QuickBooks actually means:
| Desktop code | What QuickBooks means | What to do |
|---|---|---|
3000 | The record id is malformed for this entity — Desktop ListIDs/TxnIDs have entity-specific formats, so a QBO id or guessed value won't parse. | Use an Id previously returned by TenkeyBridge for this entity. |
3170 | The record could not be modified — commonly a value the QuickBooks UI would also refuse, or the record is held by another user or open window. | Read the raw message in Detail; close the record's window in QuickBooks, or try single-user mode. |
3175 | The record is locked by another QuickBooks user or an open window. | Close the record's window; retry after the other session finishes. |
3180 | General save error — frequent culprits are sales-tax configuration conflicts or lines referencing accounts/items that changed mid-save. | Read the raw message in Detail; it usually names the list or field involved. |
3250 | The feature the request needs is not enabled in this company file (inventory, sales tax, multicurrency, …). | Enable the feature in QuickBooks preferences, or drop the fields that need it. |
3260 | The QuickBooks user the agent session runs as lacks permission for this action. | Grant the role the permission (Company → Set Up Users and Passwords), or run the agent session as a user with sufficient rights. |
-1 | QuickBooks returned a response TenkeyBridge could not parse a status code from. | Check the agent log on the host machine; report the fault with its Detail. |
Mapped Desktop codes (3100→6240, 3120→610, 3200→5010, 3140→2500, 3070→2020) surface as their numeric QBO codes above.
Admin API errors
The Admin API (/admin/v1/*) speaks its own two-field { "error", "message" } shape too — not the QBO Fault shape above and not the OAuth shape below — see Admin API: Errors for the full table of general-purpose codes (unauthenticated, forbidden, not_found, …). The four codes below are billing-specific (#92); see the billing guide for the plan and grace-period rules behind them.
error | HTTP | What happened | What to do |
|---|---|---|---|
plan_limit_realms | 409 | POST /admin/v1/realms on a trial org that already has its one allowed realm connected. The body additionally carries checkoutPath, the org's checkout endpoint. | Subscribe (POST the checkoutPath) to lift the one-realm trial limit, or delete/reuse the existing realm. |
billing_disabled | 503 | POST .../billing/checkout or .../billing/portal-session called on a gateway with no Stripe configuration. | Nothing to do as a caller — the gateway operator hasn't configured STRIPE_* secrets yet. |
enterprise_plan | 409 | POST .../billing/checkout for an org already on the Enterprise plan. | Enterprise is managed off-platform — contact sales@tenkeybridge.com, not Stripe Checkout. |
no_customer | 409 | POST .../billing/portal-session for an org with no Stripe customer yet. | Start checkout first (POST .../billing/checkout) — a Billing Portal session needs an existing Stripe customer to open. |
OAuth errors
The OAuth endpoints (/oauth2/v1/*) speak RFC 6749, not the QBO Fault shape — errors come back as { "error", "error_description", "error_uri" }. error is the stable value to branch on; error_description says what actually went wrong.
error | HTTP | What happened | What to do |
|---|---|---|---|
invalid_client | 401 | Unknown client_id or wrong client_secret. | Send HTTP Basic auth with client_id as username, client_secret as password. |
invalid_grant (code exchange) | 400 | The authorization code is invalid, expired, already used, or was issued to a different client / redirect_uri. | Codes are single-use, and the token request's redirect_uri must exactly match the authorize request's. Restart the connect flow for a fresh code. |
invalid_grant (refresh) | 400 | The refresh token is invalid, expired, revoked, or already rotated. | Every refresh returns a new refresh token — always store the latest. If the chain is lost, reconnect. |
unsupported_grant_type | 400 | grant_type isn't one TenkeyBridge supports. | Use authorization_code (first exchange) or refresh_token (renewal). |
unsupported_response_type | 400 | /authorize called without response_type=code. | TenkeyBridge implements the authorization-code flow only. |
slow_down | 429 | Too many /authorize + /tokens requests from your IP in the last minute (shared budget across both). | Wait for Retry-After seconds, then retry. Same RateLimit-* + Retry-After headers as RATE_LIMITED. |
See the authentication guide for the full connect flow.

