DEV Community

jimioniay for FreshBooks

Posted on

Getting Started with FreshBooks NodeJS SDK - Expenses & Invoices

Getting Started with FreshBooks NodeJS SDK - Expenses & Invoices
In this tutorial, we’ll be looking into the FreshBooks NodeJs SDK and how simple and easy it is to create, update and fetch Invoices, Expenses, Clients, Items, Payments, Projects, Time Entries etc. We have done all the heavy-lifting making it super convenient for you!

We have handled http calls, http retries, Idempotency, consistent request and response structures and many more.This way you get to focus on your business logic rather than figuring out how the FreshBooks API works.

Prerequisites

  1. A FreshBooks Developer account. If you don't have one, you can create one here.
  2. Authenticate yourself on the FreshBooks API using Oauth2.0. No idea how to do that? No problem, we have an excellent tutorial here.
  3. Basic knowledge of Async, Await and Node.js.
  4. A code editor (e.g. VS Code, Sublime, Atom etc.)

Let's get started!
Install the FreshBooks Nodejs SDK

In your Node project directory, install the FreshBooks NodeJs Client via npm or yarn

npm install @freshbooks/api 
Enter fullscreen mode Exit fullscreen mode
yarn install @freshbooks/api
Enter fullscreen mode Exit fullscreen mode

Get your FreshBooks Client ID

Login to the FreshBooks Dashboard, click on the Settings/Gear Icon, then click on Developer Portal. Select your Oauth App and then note the Client ID (you’ll need it).
(By the way, this tutorial assumes you have created an existing Oauth App in the past and understand the dynamics of FreshBooks Authentication. If you haven’t, then this tutorial on how to create one.)

Instantiate the FreshBooks Client
Using the block of code, we can instantiate the FreshBooks Client:

import { Client } from '@freshbooks/api';
import winston from 'winston'; // This is optional

//This logger is also optional
const logger = winston.createLogger({
   level: 'error',
   transports: [
       new winston.transports.File({ filename: 'error.log', level: 'error' }),
       new winston.transports.File({ filename: 'combined.log' }),
   ],
});


// Get CLIENT ID from STEP 2 ABOVE
const clientId = '<CLIENT ID>';

// Get token from authentication or helper function or configuration
const token = '<BEARER TOKEN>';

// Instantiate new FreshBooks API client
const freshBooksClient = new Client(token, {
   clientId
}, logger);
Enter fullscreen mode Exit fullscreen mode

Set a value for your Client ID and your Bearer Token. This tutorial assumes you have a helper function that helps generate the bearer tokens and refresh tokens from the /auth/oauth/token endpoints. If you don’t, you can check out authentication tutorial

Confirm Instantiation
Using the function below, we can confirm the instantiations works

const confirmClientInstantiation = async () => {
   try {
       const { data: { firstName, roles } } = await    freshBooksClient.users.me()
       accountId = roles[0].accountId;
       logger.info(`Hello ${firstName}`)
       return {
           firstName,
           accountId
       }
   } catch ({ code, message }) {
       // Handle error if API call failed
       logger.error(`Error fetching user: ${code} - ${message}`)
       return {
           error: {
               code, message
           }
       }
   }
}
console.log(await confirmClientInstantiation());
Enter fullscreen mode Exit fullscreen mode

If everything works as expected you should see a response similar to the below when you invoke the function. It also returns some useful information (especially the accountid. Store in a variable as you’ll need it in other method calls).

{ firstName: 'John', accountId: 'Zz2EMMR' }
Enter fullscreen mode Exit fullscreen mode

If there is something wrong, you will receive a response that looks like this:

{
  error: {
    code: 'unauthenticated',
    message: 'This action requires authentication to continue.'
  }
}
Enter fullscreen mode Exit fullscreen mode

Create A Client
If everything works as expected, you should be able to create a Client, an Invoice, etc.
For simplicity, we'll create a Client. Once we do that, this same Client will be created immediately on the FreshBooks dashboard
we will create a Client and the same client created immediately on the FreshBooks Dashboard

const createAClient = async () => {
   let client =
   {
       fName: "John",
       lName: "Doe",
       email: 'no-reply@example.com',
   }
   console.log(accountId)
   try {
       const { ok, data } = await freshBooksClient.clients.create(client, accountId)
       return ok && { data };
   } catch ({ code, message }) {
       return {
           error: { code, message }
       }
   }
}

console.log(await createAClient())
Enter fullscreen mode Exit fullscreen mode

List Expenses
We should also be able to list Expenses using the sample block below:

//Fetch Expenses
const fetchExpenses = async () => {
   try {
       const { ok, data } = await freshBooksClient.expenses.list(accountId);
       return ok && data
   } catch ({ code, message }) {
       console.error(`Error fetching expenses for accountid:  ${accountId}. The response message got was ${code} - ${message}`)
   }
}

console.log(await fetchExpenses());
Enter fullscreen mode Exit fullscreen mode

If everything checks out, you should get a list of expenses These expenses are also listed on the FreshBooks Dashboard

{
  expenses: [
    {
       …
      id: '7538415',
      taxAmount2: null,
      taxAmount1: null,
      visState: 0,
      status: 0,
      vendor: 'FreshBooks Payments',
      notes: 'CC Payment Transaction Fee Invoice: #2021-09',
      updated: 2021-04-17T06:45:36.000Z,
      ...
    }
  ] 
Enter fullscreen mode Exit fullscreen mode

Conclusion
This implementation simply scratched the surface of the possibilities of the Node.js SDK as there are several use cases that can be achieved with it.

Top comments (0)