Rails and QuickBooks Online Integration - Part 1

It’s been a while since my four-part series on Rails/QuickBooks integration first took the world by storm by enlightening the integration path between Rails web apps and desktop installations of QuickBooks.

For those with short patience and long shoelaces please do not attempt to revisit part 1, part 2, part 3, or part 4.

Today QuickBooks Online Edition (QBOE) integration is on the agenda. That “online edition” part probably sounds sweet to the uninitiated and conjures up thoughts of blissfully simple HTTPS POSTs between your app and QBOE.

Hah! Think again.

Overview

Let’s go through the basic communication model first to ease into this adventure.

Have a Rails app that needs to integrate with the QBOE?

Cool.

Let’s say your killer contact management app needs to sync with QBOE (automatically turn contacts into QuickBooks customers).

General steps:

  1. Register your app with QuickBooks and complete setup steps (detailed later).

  2. Add a special link (detailed later) in your app that directs a client to their QBOE account. The user will then follow a series of steps in QBOE to grant access to your app.

  3. After client has granted access to your app, QBOE will notify your app of the client’s connection ticket.

  4. Store this connection ticket.

  5. Sync anytime. Let’s say a contact is added and needs to be instantly pushed over to QBOE. You get a session ticket by posting a special request to QBOE. Receive session ticket and send in next request to add contact.

Setup

Note: You must have a server certificate (SSL) from a supported root certificate authority to integrate with QBOE. Of course your application should already be setup with ssl support if it’s dealing with financial data.

  1. Register your app with IDN at appreg.intuit.com

I recommend registering the app in the production environment unless you have a paid IDN membership. The reason is that test QBOE companies are only available to paid memberships. We’ll do our own testing later with a free trial account.

Lost already? Read more about the registration process.

  1. Obtain a client certificate by generating a certificate signing request (CSR):

Generate a new key:

$ openssl genrsa -out idn.key 1024

Generate CSR:

$ openssl req -new -key idn.key -out idn-foo.csr

IMPORTANT: Common Name (Your Name) needs to be EXACTLY your.url:your.application.name

Learn more at the faq or on this thread.

  1. Get CSR signed at appreg.intuit.com

Go to site, copy and paste CSR text and sign that bad boy!

  1. Create PEM

The signing process will return a certificate. Copy the certificate to a text file and name it qboe-cert.pem. Now open the key you used to generate the CSR and paste that into the same text file above the certificate.

Verify setup

If you navigated the setup section correctly, appreg.intuit.com should now list your app status as “Active” and you should have a PEM file that we can use in just a minute…

Create QBOE account

Go to the QBOE site and signup for a free trial account.

Get Connection ticket

Before integration can occur, a QBOE account must grant access to your app via a process describe in this page on implementing connection ticket support.

It’s pretty simple really…

  1. Redirect client to https://login.quickbooks.com/j/qbn/sdkapp/confirm?appid=MyAppID&serviceid=2004&appdata=myAppData where the parameters in brackets above are described in the article linked to above.

  2. The client then follows straightforward steps to grant access.

After the last step is completed, QBOE posts back the connection ticket to your web app at the “subscribe” url you entered during the signup process at appreg.intuit.com.

For initial testing, I recommend you run a tail on your production log:

$ tail -f /var/www/apps/foo/current/log/production.log

Navigate to https://login.quickbooks.com/j/qbn/sdkapp/confirm?appid=MyAppID&serviceid=2004&appdata=myAppData

Go through the steps and watch the log file for something like this:

Processing QboeController#set_connection_ticket (for 206.154.102.247 at 2007-04-23 10:52:19) [POST]
Session ID: 903284f39c9e243b2b16fdd2cbfrab53
Parameters: {"status"=>"active", "appdata"=>"31", "action"=>"set_connection_ticket", "appid"=>"123456789", "controller"=>"qboe", "authid"=>"123456789", "conntkt"=>"TGT-186-bYCv9n3XIKV459g5g8E4Zg"}

If you see a RoutingError thrown, make sure you defined a route for the one described in the “subscribe” url.

routes.rb

map.with_options(:controller => 'qboe') do |url|
  url.qboe_set_connection_ticket  'apis/qboe/set_connection_ticket', :action => 'set_connection_ticket'
  ...
end

Get Session Ticket

Now that we have the connection ticket let’s run the first real test.

Create a session.xml file as shown below. Replace ClientDateTime, ApplicationLogin, and AppID accordingly.

session.xml

<?xml version="1.0" ?>
<?qbxml version="6.0"?>
<QBXML>
   <SignonMsgsRq>
      <SignonAppCertRq>
         <ClientDateTime>2007-01-01</ClientDateTime>
         <ApplicationLogin>foo.foo.com</ApplicationLogin>
         <ConnectionTicket>TGT-186-bYCw9n3XIKVF6Mg5g8E4Zj</ConnectionTicket>
         <Language>English</Language>
         <AppID>123456789</AppID>
         <AppVer>1</AppVer>
      </SignonAppCertRq>
   </SignonMsgsRq>
</QBXML>

Grab session ticket using curl:

$ curl -v -d @session.xml -H "Content-Type: application/x-qbxml" -E /path/to/qboe-cert.pem https://webapps.quickbooks.com/j/AppGateway

Hopefully you’ll get back a response back like this:

* About to connect() to webapps.quickbooks.com port 443
*   Trying 12.149.175.47... * connected
* Connected to webapps.quickbooks.com (12.149.175.47) port 443
* successfully set certificate verify locations:
*   CAfile: /usr/share/curl/curl-ca-bundle.crt
  CApath: none
* SSL connection using DHE-RSA-AES256-SHA
* Server certificate:
*        subject: /C=US/ST=California/L=San Diego/O=Intuit/OU=Technology Ops/CN=webapps.quickbooks.com
*        start date: 2006-06-14 00:00:00 GMT
*        expire date: 2007-06-14 23:59:59 GMT
*        common name: webapps.quickbooks.com (matched)
*        issuer: /C=US/O=RSA Data Security, Inc./OU=Secure Server Certification Authority
* SSL certificate verify ok.
> POST /j/AppGateway HTTP/1.1
User-Agent: curl/7.13.2 (i386-pc-linux-gnu) libcurl/7.13.2 OpenSSL/0.9.7e zlib/1.2.2 libidn/0.5.13
Host: webapps.quickbooks.com
Pragma: no-cache
Accept: */*
Content-Type: application/x-qbxml
Content-Length: 448

<?xml version="1.0" ?><?qbxml version="6.0"?><QBXML>   <SignonMsgsRq>      <SignonAppCertRq>         <ClientDateTime>2007-01-01</ClientDateTime>         <ApplicationLogin>foo.foo.com</ApplicationLogin>         <ConnectionTicket>TGT-186-bYCw9n3XIKVF6Mg5g8E4Zj</ConnectionTicket>         <Language>English</Language>         <AppID>108096790</AppID>         <AppVer>1</AppVer>      </SignonAppCertRq>   </SignonMsgsRq></QBXML>< HTTP/1.1 200 OK
< Date: Wed, 02 May 2007 17:33:35 GMT
< Server: Web Server
< Transfer-Encoding: chunked
< Content-Type: text/plain
<?xml version="1.0"?>

<!DOCTYPE QBXML PUBLIC '-//INTUIT//DTD QBXML QBO 6.0//EN' 'http://webapps.quickbooks.com/dtds/qbxmlops60.dtd'>

<QBXML>
  <SignonMsgsRs>
    <SignonAppCertRs statusCode="0" statusSeverity="INFO">
      <ServerDateTime>2007-05-02T17:33:37</ServerDateTime>
      <SessionTicket>V1-22-giY5HWUxN_1ztXi0$FEkaQ:123456789</SessionTicket>
    </SignonAppCertRs>
  </SignonMsgsRs>
</QBXML>
* Connection #0 to host webapps.quickbooks.com left intact
* Closing connection #0

Using the verbose (-v) flag makes curl spit out tons of data. This can help with debugging. It is likely you will get an error code back. In this is the case I recommend searching (or posting to) the QBOE IDN forum. The IDN gurus that monitor the forum are really nice people that work hard to help developers.

Next steps

Hopefully you’re getting a session ticket back at this point. If not use those forums to get up to speed and await the next exciting installment of the series…

References

SDK section on Hosted App Integration
Application Registration FAQ
http://developer.intuit.com/support/technical/?id=415
http://developer.intuit.com/support/technical/?id=408

Comment or question via
FYI: This post was migrated over from another blogging engine. If you encounter any issues please let me know on . Thanks.