Exporting Gumroad Sales to Xero

I’ve been using Gumroad for a couple of years in order to easily sell products to my audience. Those products currently include a theme framework (Bootstrap for Shopify) and various packages of my Mastering Shopify Themes course. I’ll also be using it to sell my upcoming course Mastering Shopify Apps.

Until recently, I’d been pulling sales information from Gumroad over to Xero (my accounting software) manually, and at an aggregate level. This meant I wasn’t about to get a detailed sales breakdown for all my products from within Xero itself, as well as being a bit of a pain.

To automate this process a little more, I hacked up a simple Ruby script that hooks into the Gumroad API and writes out sales information for a particular Gumroad sales period into a Xero-compatible CSV format.

It requires a little bit of manual tweaking for each period and use case, but it’s dramatically reduced the amount of time I have to spend moving the data around and gives me the detail I want inside of Xero.

You’re welcome to copy this script and use it as you see fit!

#!/bin/ruby
require 'net/http'
require 'json'
require 'csv'

# Create your own custom application on Gumroad and replace the token below.
GUMROAD_ACCESS_TOKEN = 'YOUR_OAUTH_ACCESS_TOKEN'

# Set up the date that Gumroad sends the payment to your account. This script
# will calculate the dates of the previous 2-week period (with some padding to
# account for potential time zone issues). This means you may have to manually
# remove a couple of sales falling outside the correct sales period.
PAYMENT_DATE = Time.new('2015', '09', '25')
BEFORE_DATE = PAYMENT_DATE - (6 * 24 * 60 * 60)
AFTER_DATE = BEFORE_DATE - (16 * 24 * 60 * 60)

# Maps Gumroad product names to the Inventory Item Codes I use in Xero. 
INVENTORY_ITEM_CODES = {
    :'Bootstrap for Shopify (Single Licence)' => 'BS4SF-SL',
    :'Bootstrap for Shopify (Unlimited Licence)' => 'BS4SF-UL',
    :'Mastering Shopify Themes (Course Package)' => 'MST-CP',
    :'Mastering Shopify Themes (Course + Resources Package)' => 'MST-CR',
    :'Mastering Shopify Themes (Complete Package)' => 'MST-CM',
}

sales_uri = URI('https://api.gumroad.com/v2/sales')
sales_uri.query = URI.encode_www_form({
    access_token: GUMROAD_ACCESS_TOKEN,
    before: BEFORE_DATE.strftime('%Y-%m-%d'),
    after: AFTER_DATE.strftime('%Y-%m-%d')
})

sales_response = Net::HTTP.get_response(sales_uri)
sales_json = JSON.parse sales_response.body

# Write the CSV
CSV.open("gumroad-sales-#{PAYMENT_DATE.strftime('%Y-%m-%d')}.csv", 'w') do |csv|
  csv << %w(*ContactName EmailAddress *InvoiceNumber *InvoiceDate *DueDate InventoryItemCode *Description *Quantity *UnitAmount *AccountCode *TaxType Currency)
  sales_json['sales'].each do |sale|
      csv << [
          'Gumroad',
          'support@gumroad.com',
          "GUM-#{PAYMENT_DATE.strftime('%Y-%m-%d')}",
          BEFORE_DATE.strftime('%d/%m/%Y'),
          PAYMENT_DATE.strftime('%d/%m/%Y'),
          INVENTORY_ITEM_CODES[sale['product_name'].to_sym],
          sale['product_name'],
          1,
          sale['price'].to_f / 100.0,
          210,
          'BAS Excluded',
          'USD',
      ]
  end
end