QuickBooks Web Connector and qbXML, Explained: How QuickBooks Desktop Talks to Other Software
QuickBooks Desktop has no web API. Other software reaches it through a small Windows program that polls a SOAP endpoint and passes XML messages to the company file. Here is how that loop works, what each callback must return, and what breaks, from a bridge we built and tested against Intuit's own guide.
Oct 21, 2026
The QuickBooks Web Connector is a small Windows program that sits next to QuickBooks Desktop and, on a schedule, calls a SOAP web service you host. Your service hands it qbXML requests ("list the active customers", "add this invoice"), the Web Connector passes them to the open company file, and sends QuickBooks' qbXML responses back to you. QuickBooks Desktop has no web API of its own, so this loop is how a web application, an ERP, a CRM or an AI assistant reaches it. Below: the callbacks, the .qwc file, the qbXML itself, and what breaks, from a bridge we built and tested against the protocol in Intuit's own programmer's guide.
How the Web Connector works
The direction surprises most developers: your service never calls QuickBooks. The Web Connector calls you. It polls on a schedule, so it works from behind a firewall without opening any port on the accounting machine.
One run, start to finish:
- The Web Connector calls
authenticatewith the user name and password configured for your service. - If you accept, it opens the company file and calls
sendRequestXML. You return a qbXML request. - It passes your request to QuickBooks and returns the answer through
receiveResponseXML. You return how far along you are, as a percentage. - Below 100, it calls
sendRequestXMLagain. At 100, it stops and callscloseConnection. - If you return a negative number at any point, it calls
getLastErrorand shows your message to the user.
The six callbacks your service must answer
Intuit's QBWC Programmer's Guide (version 2.0, still the reference) lists six required methods, all in the http://developer.intuit.com/ namespace:
| Callback | What the Web Connector sends | What you return |
|---|---|---|
authenticate | user name, password | an array: a session ticket, then "" (use the open company file), none (nothing to do), nvu (bad credentials) or busy |
sendRequestXML | ticket, company file, country, qbXML major and minor version | a qbXML request, "" if there is nothing to send, or NoOp to pause for 5 seconds |
receiveResponseXML | ticket, QuickBooks' qbXML response, an HRESULT and message if the request processor failed | percent done (100 means finished), or a negative number on error |
connectionError | ticket, HRESULT, message | done to stop, "" to retry with the open company file, or a company file path to try instead |
getLastError | ticket | the message to show the user |
closeConnection | ticket | a status message, shown in the Web Connector's status column |
Optional ones exist too: clientVersion to reject an old Web Connector, a server version callback, and three for interactive sessions.
Two details from building it:
- The guide contradicts itself on
authenticate. Its prose describes the returned array as if the first element were the company file. Its own sample code, and every other callback, treat element 0 as the session ticket and element 1 as the company or status. Follow the sample. - The server version callback has two names. The guide's reference calls it
getServerVersion; community implementations answerserverVersion. Our endpoint answers both.
The .qwc file
The QuickBooks user installs your service by adding a small XML file to the Web Connector. It tells it where to call and how often:
<?xml version="1.0"?>
<QBWCXML>
<AppName>quickbooks-bridge</AppName>
<AppID></AppID>
<AppURL>https://bridge.example.com/qbwc</AppURL>
<AppDescription>Syncs customers and writes approved invoices</AppDescription>
<AppSupport>https://bridge.example.com/qbwc</AppSupport>
<UserName>bridge</UserName>
<OwnerID>{57F3B9B1-86F1-4FCC-B1EE-566DE1813D20}</OwnerID>
<FileID>{90A44FB5-33D9-4815-AC85-BC87A7E7D1EB}</FileID>
<QBType>QBFS</QBType>
<Scheduler>
<RunEveryNMinutes>15</RunEveryNMinutes>
</Scheduler>
</QBWCXML>
AppURL must be HTTPS. The Web Connector accepts plain http only for localhost, for development. The password is not in the file: the user types it into the Web Connector, which sends it to authenticate on every run.
What qbXML looks like
A request asking for up to 25 active customers:
<?xml version="1.0" encoding="utf-8"?>
<?qbxml version="13.0"?>
<QBXML>
<QBXMLMsgsRq onError="stopOnError">
<CustomerQueryRq requestID="customers">
<MaxReturned>25</MaxReturned>
<ActiveStatus>ActiveOnly</ActiveStatus>
</CustomerQueryRq>
</QBXMLMsgsRq>
</QBXML>
And one adding an invoice:
<InvoiceAddRq requestID="invoice-1">
<InvoiceAdd>
<CustomerRef><FullName>Abercrombie, Kristy</FullName></CustomerRef>
<TxnDate>2026-10-21</TxnDate>
<RefNumber>1042</RefNumber>
<InvoiceLineAdd>
<ItemRef><FullName>Installation</FullName></ItemRef>
<Desc>On-site install</Desc>
<Quantity>2</Quantity>
<Rate>125.00</Rate>
</InvoiceLineAdd>
</InvoiceAdd>
</InvoiceAddRq>
Every response carries a status as attributes: statusCode="0" is success, 1 on a query means nothing matched, anything else is an error with a readable statusMessage.
What breaks
- Element order. qbXML is validated against a schema that fixes the order of elements. Swap
TxnDateandRefNumberand QuickBooks rejects the request. Build requests from typed structures, never by concatenating strings. - Version.
sendRequestXMLtells you which qbXML version the installed QuickBooks supports. Write at that version or below. We cap at 13.0 and drop lower when the installed version reports less. - References by name.
FullNamemust match a customer or item in the company file exactly. If it doesn't, QuickBooks answers withstatusCode="3140", an invalid reference, and names it. Match names before you send, and report the error rather than retrying. - Errors that go nowhere. If
receiveResponseXMLreturns a positive number after a failed request, the Web Connector carries on and the user never hears about it. Return a negative value and letgetLastErrorsay what happened. - The machine. The Web Connector runs on Windows, next to QuickBooks, and only when QuickBooks can open the company file. If the PC is off, nothing syncs. Design for delays of hours, not seconds.
What we built
Our bridge, open source on GitHub, implements the Web Connector side in Go: the six callbacks plus the optional ones, a queue of qbXML requests per session, typed requests in schema order, and a .qwc generator. It reads customers and writes the invoices waiting in an outbox. We tested it the way the Web Connector drives it: a full session from authenticate to closeConnection, a rejected password, and QuickBooks' error 3140 on an unknown item, which surfaces through getLastError.
What we haven't done yet is run it against a live QuickBooks Desktop company file, which needs a Windows machine with QuickBooks installed. The QuickBooks Online half of the same bridge runs against a live sandbox; that part is in QuickBooks API integration.
If your business still runs QuickBooks Desktop, read what Intuit is ending and what to do about it before you invest in anything new around it.
Related: QuickBooks API integration, QuickBooks MCP, and QuickBooks automation with AI.