Emailed invoices are easy to ignore. But a physical letter? Mailed invoices can earn higher response rates–especially for overdue payments. One brand study reported that the majority (59%) of its customers failed to pay on first billing when emailed and needed additional reminders. Yikes. On the other hand, only 29% of those billed by direct mail failed to pay on first billing and required follow-up.
In this tutorial, we will build a simple Rails app that acquires all invoices associated with your invoicing system and gives you the option to send the invoices by mail programmatically using the Lob API. Read on for the full tutorial or skip ahead to GitHub code.
Setting Up
This tutorial is written primarily for Rails, but the concepts can be translated across languages.
What you’ll need
- A free RapidAPI account to test API calls and export code snippets
- A Lob account to send the physical mail
- An invoicing system (we’ll use Freshbooks’ free 30 day trial)
What you’ll build
We’ll build this project in Rails and define two routes: get_invoices
, and send_invoice
. Using ERB and the Lob invoice template, we will dynamically generate an invoice with all of the Freshbooks invoice details filled out. We will call the Freshbooks and Lob APIs using RapidAPI. RapidAPI allows us to test the API calls in our browser and see a JSON response. It will also export the API call as a code snippet in the language of your choice.
What the final project will do
This tutorial will walk through how to programmatically send an invoice from Freshbooks via the US Postal Service with Lob. Note, we won’t be covering how to build a frontend.
When the app is visited, all of your Freshbooks’ invoices will rendered in a list along with a Send Mail button. When you click the Send Mail button, ERB will dynamically generate an invoice with all of the invoice information.
The resulting invoice document will look something like this, but you can customize it as you see fit.
Finally, the app will send the invoice through the United States Postal Service via Lob’s API. Pretty cool, right?
Building the Project
Let’s walk through the steps to build this application. If you reach a roadblock, you can compare your code to the finished project in this repo.
Step 1: Create an invoice controller
Before we mail the invoices out, we’ll need to retrieve them! The invoice controller will send all the invoices to the frontend and populate the app. Since we’re using Freshbooks as our invoicing system (thank you, 30 day free trial!), we’ll call our controller the Freshbooks controller. Here are the steps we took:
- Make a Freshbooks account
1a. Travel to https://my.freshbooks.com/#/signup and create an account.
1b. Populate a new business with invoices or import your existing business invoices. We chose to make Dave’s Construction business because, hey, who wouldn’t want to build stuff all day?
- Call the Freshbooks API
getInvoices
endpoint on RapidAPI
2a. The first thing you will need to do is generate an access token. Head to https://rapidoauth.com/freshbooks
2b. After you generate the access token, you’ll be taken directly into the RapidAPI testing environment. Test out your new access token with the getIdentityInfo
endpoint!
2c. Look through the JSON response and find your Freshbooks accountID. (response -> roles -> accountId). Copy this ID onto your clipboard.
2d. Go to the getInvoices endpoint. Enter your access token and paste your account ID. Expand the optional parameters section and add the word “lines” to the “include” parameter. This addition will give us access to all the details about each item on an invoice.
2e. Click the TEST Function button to call the API!
2f. Sign in to generate a code snippet in Ruby. You can call an API without a RapidAPI account, but you’ll need one to access the code snippet.
3. Build a custom route and controller
3a. Start a new Rails project (rails new [project_name]
) or navigate to an existing project.
3b. Type rails g controller freshbooks
into your terminal.
3c. Define a custom route ( get 'freshbooks/get_invoices', :to =>
‘freshbooks#get_invoices’) in your config/routes.rb file.
3d. Write gem 'rapidapi', '~> 0.1.3'
in your Gemfile. Then, run bundle install in Terminal.
3e. In your FreshbooksController, define a method called get_invoices
and copy and paste your RapidAPI getInvoices
code snippet that was saved from the previous step.
Note: Prefix each RapidAPI class with a double colon “::”. These colons tell Rails to not implicitly call ‘self’ before calling the RapidAPI class.
3f. Finally, write render json: JSON.pretty_generate(root[‘payload’][‘response’]
[‘result’][‘invoices’])
as the last line in your controller.
3g. Start your server with rails s
and navigate to localhost:3000/freshbooks/get_invoices. You should see a JSON response of all the invoices within your Freshbooks account.
Ta-da!
Your invoice controller should look like this:
def get_invoices require 'rapidapisdk' ::RapidAPI.config(project: "LobFreshbooks", token: ‘############’) root = ::RapidAPI.call('FreshbooksAPI', 'getInvoices', { 'accessToken': '###################', 'accountId': '#####', 'include': 'lines' }) render json: JSON.pretty_generate(root['payload']['response']['result']['invoices']) end
Step 2: Make a Lob Controller
Now that the invoicing controller is all set, we can move onto the Lob controller. The Lob controller will actually call the Lob API and send the invoice as a physical piece of mail (or a virtual one if we’re in test mode). Let’s build it!
Since this process is slightly more complicated than the invoice controller, we’ve divided it into three sections: set up, connect to RapidAPI, generate invoice.
A) Set up your Lob account and Lob controller
To kick this process off, we’ll create a Lob account and skeleton Lob controller.
1.Create a Lob account and get your Test API Key
1a. Head to Lob to sign up for an API key: https://dashboard.lob.com/#/settings/keys
1b. Copy the “Test API Key” onto your clipboard.
Why are we using the test API key? This key allows us to make calls and test them without sending out physical mail just yet. Another bonus? We won’t be charged for calls using a test API key.
2. Set up your Lob controller
2a. Run rails g controller Lob
in Terminal.
2b. Create another custom route in your routes.rb file to look like get 'lob/send_invoice', :to => 'lob#send_invoice'
.
2c. Define a method in your LobController called send_invoice
.
B) Connect your Lob controller to the Lob API with RapidAPI
Here’s where it gets interesting…We will be sending our Freshbooks invoice details along with our AJAX call to the send_invoice route.
1. Connect to RapidAPI to call Lob’s createLetter endpoint
1a. This step should feel familiar! Go to the createLetter endpoint on RapidAPI’s Lob package. Paste your Lob “Test API Key” into the apiKey form.
1b. Test the API call and see the JSON results. Generate the code snippet in Ruby. Copy and paste this code snippet directly into your send_invoice method.
Note: Again, prefix each RapidAPI class with a double colon “::”.
2. Fill out the API parameters
2a. Create letterTo
and letterFrom
address objects. The letterTo and letterFrom parameters in your Lob RapidAPI call take a JSON address object that looks like this:
‘letterTo’: JSON.generate({ name: params['name'], address_line1: params['address_line_1'], address_city: params['city'], address_state: Lob.state[params['state'].to_sym], address_country: Lob.iso[params['country']], address_zip: params['zip_code'] })
Notice that each line of the letterTo address object contains an invoice parameter.
2b. Next, implement state and country conversions. Why do we need these? The Freshbooks JSON response returns full country and state names (ie. “California” or “India”) but the Lob API takes state and country abbreviations.
Since the address_country
and address_state
parameters access a Lob model, we’ll need to generate a new Lob model (rails g model Lob
). Take a look at our Lob model to see how we built it and see the two country and state hash objects. Then, implement the two state and country hash objects into two methods respectively.
2c. Fill in the letterFrom parameter with your company’s information:
'letterFrom': JSON.generate({ name: "Dave's Construction", address_line1: "600 California St.", address_city: 'San Francisco', address_state: 'CA', address_country: 'US', address_zip: '94109' })
C) Generate an invoice programmatically within your Lob controller
Finally, we’ll use ERB to generate an invoice within the Lob controller.
1. Create an .erb file
1a. If Rails hasn’t already created a lob/send_invoice.html.erb within your views folder, go ahead and do so now.
1b. Navigate to Lob’s invoice template and copy Lob’s invoice template into the send_invoice.html.erb file that you just created.
2. Alter the file to generate the invoice based on Freshbooks params
2a. Access to the @params
variable we defined in our LobController in the .erb file. Check out our finished .erb file here to get an idea of how you should modify this file.
3. Modify send_invoices method in LobController to generate the .erb file
3a. Bind the @params
variable to the .erb file to generate its result using this code snippet.
3b. Add these four lines to your code above the RapidAPI.call function
@params = params Dir.chdir(File.dirname(__FILE__)) erb_string = File.read('../views/lob/send_invoice.html.erb') renderer = ERB.new(erb_string) result = renderer.result(binding)
The first line just ensures that our master directory is set as our current directory, then we read our .erb file. Once we have read our .erb file we need to create a new instance of the ERB class, pass our .erb file as an argument, and render the result. The “binding” key word is Rails’ way of passing all of our needed variables (in this case, the instance variable @params) to our template.
3c. Our RapidAPI.call method takes a file parameter. Go ahead and set the variable “result” as our file. The final line of your send_invoice method should say render json: response
.
Boom!
Once your are finished, your LobController#send_invoice method should look similar to this:
def send_invoice require 'rapidapisdk' ::RapidAPI.config(project: [YourRapidProject], token: [YourRapidProjectKey]) @params = params Dir.chdir(File.dirname(__FILE__)) erb_string = File.read('../views/lob/send_invoice.html.erb') renderer = ERB.new(erb_string) result = renderer.result(binding) response = ::RapidAPI.call('Lob', 'createLetter', { 'apiKey': '###########################', 'letterTo': JSON.generate({ name: params['name'], address_line1: params['address_line_1'], address_city: params['city'], address_state: Lob.state[params['state'].to_sym], address_country: Lob.iso[params['country']], address_zip: params['zip_code'] }), 'letterFrom': JSON.generate({ name: "Dave's Construction", address_line1: "600 California St.", address_city: 'San Francisco', address_state: 'CA', address_country: 'US', address_zip: '94109' }), 'color': true, 'file': result }) render json: response end
Step 3: Build a Frontend
We won’t go into too much detail about how your frontend should look, but just know that you should have two AJAX calls: one to the freshbooks/get_invoices route, and another to your lob/send_invoice route. This project populates the frontend with invoices on the initial loading of the app and displays buttons for each invoice to send by mail respectively. The frontend uses React.js. Feel free to use our sample frontend as a way to get this app up and running.
get_invoices: $.get({ url: 'freshbooks/get_invoices' }); send_invoice: $.get({ url: 'lob/send_invoice', data: { name: invoice.fname + " " + invoice.lname, amount: invoice.amount, organization: invoice.organization, address_line_1: invoice.street, city: invoice.city, state: invoice.province, zip_code: invoice.code, country: invoice.country, invoice_number: invoice.invoice_number, customer_id: invoice.customerid, create_date: invoice.create_date, lines: invoice.lines } }).done(function(res) { console.log(res); });
Conclusion
While this tutorial focuses on Freshbooks, you can replicate the project with any invoicing system. RapidAPI has Shopify, SquareEcommerce and Stripe, or you could call the APIs directly.
Let us know what you build and feel free to raise an issue on GitHub with any questions or concerns. Happy invoicing!
Leave a Reply