Logo
Home

Building Smarter with Intuit: Batch without a Scratch

As part of a new series of articles around best practices for developing applications with Intuit APIs called “Building Smarter with Intuit”, we’re sharing insights and tips on optimizing everything from authorization to APIs to advanced platform capabilities. Stay tuned for more articles in this series designed to help you level up your app development on the Intuit developer platform.

The second article in this series covers the batch operation. Let’s start with a quick recap. Instead of sending requests individually, you can send batches of requests to the QuickBooks Online (QBO) accounting API. You do this by constructing payloads as you normally would and then wrapping them in a BatchItemRequest object. Within this object, you’ll find a number of child attributes. The table below outlines these.

AttributeNecessityJSON ExampleNote

bld
Required“bId”: “CA100”A unique identifier for the object.
operationConditionally required“operation”: “create”The operation you want to perform against the resource. Valid values include: create, update, or delete. Not required for query operations.
optionsDataConditionally required“optionsData”: “void”Required for void operations. Pass the value as ‘void’ while setting the operation to ‘update’.
resourceNameOptional“Customer”: {
   “DisplayName”: “Intuit Inc.”
}
This is where you’ll populate a full payload for create, update, or delete operations.
QueryOptional“Query”: “select * from Bill”Generally, you’ll declare query or resourceName
There are a few items to be aware of if you’re considering using the batch operation:
  • Rather than using the standard resource endpoints, the batch operation has its own endpoint: base URL/v3/company/<realmID>/batch.
  • The maximum number of payloads in a single batch request is 30.
  • The maximum number of batch requests is 40 per minute per realmID.
  • Execution order of each batch object should not be assumed. For example, the first chronological object in your batch may not be executed first.
  • Each object in your batch request is treated independently. A given object cannot be dependent on another object within the same batch request. For example, you are unable to create a customer record and then apply an invoice to that newly created customer within the same batch request.
  • A batch request is authenticated once. This authentication applies to all objects within the batch request.
  • The maximum number of objects that can be returned in a response is 1000.
Additionally, there are some key benefits:
  1. Cleaner and more streamlined code.
  2. Reduced network latency – ‘one’ call instead of multiple asynchronous calls.
  3. Cost savings – if your infrastructure is charged by volume of requests, this can help reduce the overall cost.

With this knowledge in hand, let’s cover a few primary use cases.

Note: for greater legibility, we’ll only include a small number of attributes in the snippets below.

Use case 1: initial data pulls

A new user has just connected your app to their QBO file. Generally, one of the first things you might carry out is an initial data pull that will usually involve multiple resources and endpoints. For example, you may want to pull all customer records, vendor records, and general ledger accounts, as well as a call towards companyInfo. Doing this via a batch operation would look something like this:

{
  "BatchItemRequest": [
    {
      "bId": "CA101", 
      "Query": "SELECT Id, DisplayName, PrimaryEmailAddr, Balance FROM Customer WHERE Active = true"
    }, 
    {
      "bId": "CA102", 
      "Query": "SELECT Id, DisplayName, PrimaryEmailAddr, Balance FROM Vendor WHERE Active = true"
    }, 
    {
      "bId": "CA103", 
      "Query": "SELECT Id, FullyQualifiedName, Classification, Active, AccountSubType FROM Account"
    }, 
    {
      "bId": "CA104", 
      "Query": "SELECT * FROM CompanyInfo"
    }
  ]
}

In this example, we’re able to get all the data we need to successfully onboard a new user and we did it all in one single request towards a single endpoint.

Use case 2: onboarding or creating default records

Your app may also have a need to create defaults such as default customer records, clearing accounts, products & services, etc. Doing this via a batch operation might look something like this:

{
  "BatchItemRequest": [
    {
      "bId": "CA105", 
      "operation": "create",
      "Customer": {
        "DisplayName": "Intuit General Store"
      }
    }, 
    {
      "bId": "CA106", 
      "operation": "create", 
      "Account": {
        "Name": "General Store Clearing",
        "Classification": "Asset",
        "AccountSubType": "OtherCurrentAssets"
      }
    }, 
    {
      "bId": "CA107", 
      "operation": "create", 
      "Item": {
        "Name": "General Store Sale",
        "Type": "NonInventory",
        "IncomeAccountRef": {
          "name": "Sales of Product Income",
          "value": "79"
        },
        "ExpenseAccountRef": {
          "name": "Bank Charges",
          "value": "8"
        }
      }
    }
  ]
}

We’ve now created all the default records that our integration requires to successfully operate.

Use case 3: cleanup, migration, or high transaction volume

Perhaps your app provides functionality to clean up a set of books or migrate from another accounting software to QBO. With these use cases, you’ll likely be hitting the maximum number of payloads (30) in a single batch operation. A great way to systematically approach this is to:

  • Think about the operations you need to carry out
    • For cleanup, it will mostly be update operations with some delete operations (e.g. for duplicate transactions)
    • For migration, it will likely be entirely create operations
  • Think about the different resources/entities you need to impact
    • Wherever possible, recreate transactions using the natural object – e.g. invoices, payments, bills, bill payments, expenses as opposed to journal entries
  • Start with a call towards CompanyInfo and Preferences
  • Then, create/update list-based records first – customers vendors, GL accounts, classes/locations (if applicable) using batch operations
  • After, create/update transactions using batch operations
  • Finally, query reports to reconcile vs. known balances

The order of operations will vary from app to app and from use case to use case, but this can be used as a starting point. When raising these batch operations, consider counting the number of objects you need to impact and then divide by 30 to get to the total number of batch requests you’ll need to send.

For example, if you had the following ‘update’ scenario:
  • 67 customer records
  • 34 vendor records
  • 483 invoices
  • 206 bills
You could split it up as follows:
  • Customer: 67 customer records/30 = 3 batch requests
  • Vendor: 34 vendor records/30 = 2 batch requests
  • Invoice: 483 invoices/30 = 17 batch requests Bill: 206 bills/30 = 7 batch requests

The pseudo logic would look something like this, repeating once you’ve hit the maximum number of payloads (30):

{
      "bId": "CA108", 
      "operation": "update",
      "Customer": {
        ...
      },
      "bId": "CA109", 
      "operation": "update",
      "Customer": {
        ...
      },
        ...
}

The result has been reduced to ~30 requests from what would have been almost ~800 individual requests.

SDKs

If you are using either our .NET, Java, or PHP SDK, you’re in luck. Pre-built methods for batch operations are available.

  • Learn more about using the batch operation with the Java SDK here
  • Learn more about using the batch operation with the .NET SDK here
  • Learn more about using the batch operation with the PHP SDK here

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *