Creating a Pure Python Web Dashboard with the QuickBooks API
Tags: quickbooks, python, webdev, dashboard
Published: 2022-03-25 15:20:25

[QuickBooks](https://quickbooks.intuit.com/) is flexible, powerful accounting software, used by businesses and individuals alike. It also has a [robust API](https://developer.intuit.com/app/developer/qbo/docs/develop) - and I'm going to show you how to use it. We're going to build a public dashboard, displaying company revenue by month.

We're building it with [Anvil](https://anvil.works/), so we can build and deploy this app entirely in Python (no HTML or JavaScript required!). We're not just driving the QuickBooks API with Python code -- we're building the front-end, including interactive plots in the browser, with Python too!

Here's the finished app:

![The app we're going to build.](https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png)

[Open the app here](https://quickbooks-revenue-viewer.anvil.app), or read on for a run-down of how it's built!

Here's how we put this dashboard together:

1. [Create our apps and set up credentials](#1-setting-up-our-apps-and-credentials)
2. [Authenticating and getting API tokens](#2-getting-api-tokens)
3. [Calling the QuickBooks API to get our data](#3-call-the-quickbooks-api)
4. [Display our data to our users](#4-display-our-data)

You can open the app's source code and follow along -- just click below:

[Clone the app!](https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH)

Ready? Let's begin.

---

## 1. Setting up our apps and credentials

![Creating an Anvil app is fast and easy.](https://anvil.works/docs/img/create-app.png)

To get started, we just head to the [Anvil App Editor](https://anvil.works/build), hit 'New Blank App' and choose 'Material Design'. This gives us a layout where we can start dragging and dropping components, such as a title.

Then, deploying the app is as simple as clicking 'Publish App' in the app's settings, choosing a URL, and hitting 'Apply'.

Now our app is available to anyone on the web - but it's not very exciting yet! To start pulling accounting data from Quickbooks, we'll need to set up an account there too.

![Creating an Intuit app to provide data to our Anvil app.](https://anvil.works/articles/img/quickbooks-revenue-viewer/create-intuit-app.png)

We head to the [Intuit developer page](https://developer.intuit.com/app/developer/homepage) and sign up there for a developer account. From there, we can create a [sandbox company](https://developer.intuit.com/app/developer/qbo/docs/develop/sandboxes), which is a dummy company that comes pre-filled with some example accounting data.

Once we've got our sandbox company all set up, we go to the [Dashboard](https://developer.intuit.com/app/developer/dashboard) to create an Intuit app. This is the entity that provides us with authentication details, so that our Anvil app can access our QuickBooks data.

Then, from the Dashboard, we can access the credentials from our Intuit app; we're looking for a `Client ID` and `Client Secret`, and they can be found under the 'Keys and OAuth' section.

![An example of the credentials we need.](https://anvil.works/articles/img/quickbooks-revenue-viewer/client-id-and-secret.png)

We store these in our Anvil app as [App Secrets](https://anvil.works/docs/security/encrypting-secret-data), so we can access them later from code.

Now we're armed with the credentials we need, we can get started on the authentication flow for our Anvil app!

## 2. Getting API tokens

To access the QuickBooks API, our app needs API tokens. We have to get those interactively (via OAuth), but they're then valid for 100 days, so we can store them in our database and use them to fetch data whenever our app is opened. (We're not going to get into a full OAuth tutorial here -- you can see how it works in [our app's source code](#see-the-code), or read a [more detailed guide](https://developer.intuit.com/app/developer/qbo/docs/develop/authentication-and-authorization/oauth-2.0) in the QuickBooks docs).

![Authenticating our app for the first time with OAuth.](https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/first-authentication.gif)

Once we have tokens, we store them in our app's [built-in database](https://anvil.works/docs/data-tables), using Anvil's [built-in encryption](https://anvil.works/docs/security/encrypting-secret-data). When the token expires, we'll need to repeat the OAuth login process, but that's pretty quick:

![Reauthenticating - once we've already connected our two apps - is really fast!](https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/authenticating.gif)

## 3. Call the QuickBooks API

Now our app has all the credentials it needs to start making calls to the QuickBooks API. We're going to use the [ProfitAndLoss](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/profitandloss) endpoint to retrieve data about our total income over the last year, grouped by month.

Here's the server function:

```
@anvil.server.callable
def get_past_yearly_data():
  # The 'quickbooks_auth' table has one row, with all our tokens in. Fetch it:
  row = app_tables.quickbooks_auth.get()

  # Decrypt the Access Token
  access_token = anvil.secrets.decrypt_with_key('tokens_key', row['encrypted_access_token'])

  # Hit the ProfitAndLoss endpoint
  today = date.today()
  resp = requests.get(
    url=f'https://sandbox-quickbooks.api.intuit.com/v3/company/{row['realm_id']}/reports/ProfitAndLoss',
    headers={
      "accept": "application/json",
      "authorization": f"Bearer {access_token}",
      "content-type": "application/json",
    },
    params={
      'start_date': f'{today.year - 1}-{today.month + 1}-01',
      'end_date': today.isoformat(),
      'summarize_column_by': 'Month',
      'minorversion': "57"
    }
  ).json()
```

Here we see the code for the API call; we get the access token from our Data Table and decrypt it, then make a `GET` request using the Python [requests](https://pypi.org/project/requests/) package.

The data that comes back is a little gnarly ([here's a sample](https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/profitandloss)), but it's nothing we can't fix with a few list comprehensions:

```
  months = [col["ColTitle"] for col in resp["Columns"]["Column"]][1:]
  summary = [col["Summary"] for col in resp["Rows"]["Row"] if col["Summary"]["ColData"][0]["value"] == "Total Income"][0]["ColData"][1:]
  incomes = [item["value"] for item in summary]

  return months, incomes
```

## 4. Display our data

Now for the easiest part: Call that `get_past_yearly_data()` function from the browser, and put the results into a [Plotly chart](https://anvil.works/docs/client/components/plots).

We create a Plot component using Anvil's [drag-and-drop GUI editor](https://anvil.works/articles/python-gui-builder-web), and call it `revenue_plot`:

![Creating a Plot component with the Anvil editor](https://anvil-website-static.s3.eu-west-2.amazonaws.com/blog/quickbooks-revenue-viewer/add-plot-component.gif)

Anvil lets us [call server functions](https://anvil.works/docs/server) directly from browser code. Our server function returns two lists: one with all the months for which we have data, and one with the incomes for those months.

```
  # This code runs in the browser:
  months, incomes = anvil.server.call('get_past_yearly_data')
```

Now we can import the Plotly API:

```
import plotly.graph_objects as go
```

...and make a bar chart:

```
self.revenue_plot.data = go.Bar(
    x = months,
    y = incomes,
    marker={'color': '#39bfbc'}
)

self.revenue_plot.layout = go.Layout(
    title=go.layout.Title(text="Last year's monthly income", x=0.5),
    yaxis_title="Income (USD)"
)
```

And that's it! Here's our finished app:

![Our app, showing the data we got from our API call represented in a Plotly plot.](https://anvil.works/articles/img/quickbooks-revenue-viewer/finished-app.png)

## See the code

If you want to see the source code for this app, you can click [here](https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH) to clone it!


## Go even further

Of course, we've only barely scratched the surface of what it's possible to do with the QuickBooks API. Using this framework, you could build a fully featured dashboard and make much more use of Plotly's interactive features. Have a go at extending what we've built today!

[Clone the app!](https://anvil.works/build#clone:DT32LOG3M6456ZZV=OXVM6GNKPEYIXP3R5PFVGUCH)

## More about Anvil

If you're new here, welcome! [Anvil](/) is a platform for building full-stack web apps with nothing but Python. No need to wrestle with JS, HTML, CSS, Python, SQL and all their frameworks – just **build it all in Python**.

[Try Anvil for free!](https://anvil.works/build)