Follow

QB Remote Connector

QuickBooks SDK is a time tested option while doing custom programming against any flavor of QuickBooks Desktop edition. This SDK is based on COM with two interfaces: QBFC and QBXML.

QBFC uses pre-defined objects to build XML requests, whereas much of the plumbing has to be done by you with QBXML that includes XML serialization and deserialization.

While it is a breeze to consume the SDK from .NET based languages, the same is not true with other popular languages/frameworks such as PHP, Java, Node.js etc., because of the SDK’s roots in COM. Common problem across programming languages/frameworks is connecting to a remote instance of QuickBooks and perform pull/push of data.

Remote Connector™ for QuickBooks
(http://www.remoteconnector.com) provides answers for the COM headache and remote connectivity and best of all it is FREE. It is language/framework agnostic since it uses QBXML as the medium while communicating with QuickBooks. Please check the website on how to install and configure the product.

This Blog will not delve too much into the functioning of Remote Connector™ for QuickBooks but will focus on an issue observed while using it through QB SDK (http://www.remoteconnector.com/#1#quickbookssdk) and suggests a fix .

As per the provided documentation a simple POST request has to be issued to the Remote Connector™ for QuickBooks in QBXML format and response is returned in the HTTP response body. However, when we’ve sent a CustomerAdd request through C# code, received empty value in response.

qbconnector_01

Re verified the Request QBXML which has no issues at all:

<?xml version="1.0" ?>
<?qbxml version="13.0"?>
<QBXML>
  <QBXMLMsgsRq onError="stopOnError">
    <CustomerAddRq>
      <CustomerAdd>
        <Name>John Doe</Name>
        <IsActive>1</IsActive>
        <Email>johndoe@johndoe.com</Email>
        <CreditLimit>0.00</CreditLimit>
      </CustomerAdd>
    </CustomerAddRq>
  </QBXMLMsgsRq>
</QBXML>

Checking the logs of QB didn’t reveal much, hence went through the Verbose log maintained by the Remote Connector™ for QuickBooks. Looking at the HTTP headers gave us a clue and added another Header to the HTTP request: X-AcctSyncInteractionType with 0 as the value and voila the same QBXML request worked this time:

qbconnector_02

qbconnector_03

Below shows the other Headers tried to solve the issue, however including/omitting them didn’t make any difference. These may come handy down the road, one never knows!!!!

Header Name Header Value
X-AcctSyncVersion 1.0.0
X-AcctSyncApplicationName Provide a name, ex: QB Synchronizer.
X-AcctSyncConnectionMode 3
X-QBXMLVersion 13.0 This value has to reflect the QB XML version being used by you.
X-QBPOS False
X-AcctSyncMIC Unique Numeric value. Used DateTime.Now.Ticks.ToString() from C#.

Please check the sample code used to verify the Remote Connector™ for QuickBooks.

Using HTTPWebRequest

private static string Exec_QBRequest_HTTPWebRequest(string xmlRequestData)
        {
            //Include the User Name and Password as configured in Remote Connector.
            string userName = "<YOUR USER NAME>", passWord = "<YOUR PASSWORD>";
            //Provide the URL where Remote Connector is installed, including the Port number.
            string strURL = "http://10.0.0.179:8166";
            HttpWebRequest qbRequest = (HttpWebRequest)WebRequest.Create(strURL);
            qbRequest.Headers.Add("Authorization", string.Format("Basic {0}", Convert.ToBase64String(Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, passWord)))));
            qbRequest.Method = "POST";
            //
            qbRequest.Headers.Add("Accept-Encoding:gzip, deflate");
            qbRequest.UserAgent = "Osmosys QuickBooks Integrator - www.osmosys.asia";
            //
            byte[] dataToSend = Encoding.UTF8.GetBytes(xmlRequestData);
            qbRequest.KeepAlive = false;
            qbRequest.ServicePoint.Expect100Continue = false;
            qbRequest.ContentLength = dataToSend.Length;
            //IMPORTANT HEADER - if omitted will get a blank string from the Remote Connector.
            qbRequest.Headers.Add("X-AcctSyncInteractionType", "0");
            //Below are optional Headers.
            qbRequest.Headers.Add("X-AcctSyncVersion", "1.0.0");
            qbRequest.Headers.Add("X-AcctSyncApplicationName", "QB Data Synchronizer");
            qbRequest.Headers.Add("X-AcctSyncConnectionMode", "3");
            qbRequest.Headers.Add("X-QBXMLVersion", "13.0");
            qbRequest.Headers.Add("X-QBPOS", "False");
            qbRequest.Headers.Add("X-AcctSyncMIC", DateTime.Now.Ticks.ToString());
            //
            Stream requestStream = qbRequest.GetRequestStream();
            requestStream.Write(dataToSend, 0, dataToSend.Length);
            requestStream.Close();
            //
            HttpWebResponse qbResponse = (HttpWebResponse)qbRequest.GetResponse();
            Stream responseStream = qbResponse.GetResponseStream();
            StreamReader myStreamReader = new StreamReader(responseStream, Encoding.Default);
           //
            string xmlResponse = myStreamReader.ReadToEnd();
            //
            myStreamReader.Close();
            responseStream.Close();
            qbResponse.Close();
            //
            return xmlResponse;
        }

Using HTTPClient

private static string Exec_QBRequest_HTTPClient(string xmlRequestData)
        {
            string xmlResponse = "";
            //Provide the URL where Remote Connector is installed, including the Port number.
            string strURL = "http://10.0.0.179:8166";
            //Include the User Name and Password as configured in Remote Connector.
            string userName = "<YOUR USER NAME>", passWord = "<YOUR PASSWORD>";
            //
            var task = Task.Factory.StartNew(() => {
                using (var client = new HttpClient())
                {
                    client.BaseAddress = new Uri(strURL);
                    var credentials = Encoding.ASCII.GetBytes(string.Format("{0}:{1}", userName, passWord));
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(credentials));
                    client.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate");
                    client.DefaultRequestHeaders.Add("UserAgent", "Osmosys QuickBooks Integrator - www.osmosys.asia");
                    client.DefaultRequestHeaders.ExpectContinue = false;
                    client.DefaultRequestHeaders.ConnectionClose = true;
                    //
                    HttpResponseMessage qbResponse = null;
                    HttpRequestMessage qbRequest = new HttpRequestMessage();
                    qbRequest.Method = HttpMethod.Post;
                    if (string.IsNullOrEmpty(xmlRequestData) == false)
                    {
                        qbRequest.Content = new StringContent(xmlRequestData);
                    }
                    //
                    //IMPORTANT HEADER - if omitted will get a blank string from the Remote Connector.
                    qbRequest.Headers.Add("X-AcctSyncInteractionType", "0");
                    //Below are optional Headers.
                    qbRequest.Headers.Add("X-AcctSyncVersion", "1.0.0");
                    qbRequest.Headers.Add("X-AcctSyncApplicationName", "QB Data Synchronizer");
                    qbRequest.Headers.Add("X-AcctSyncConnectionMode", "3");
                    qbRequest.Headers.Add("X-QBXMLVersion", "13.0");
                    qbRequest.Headers.Add("X-QBPOS", "False");
                    qbRequest.Headers.Add("X-AcctSyncMIC", DateTime.Now.Ticks.ToString());
                    //
                    qbResponse = client.SendAsync(qbRequest).Result;
                    xmlResponse = qbResponse != null ? qbResponse.Content.ReadAsStringAsync().Result : "";
                }
            });
            task.Wait();
            //
            return xmlResponse;
        }

 Posted By: Keshava Chandra, Osmosee

Are you interested? follow us and get notified of new posts

Leave A Reply