Forem

Takuya Matsuyama
Takuya Matsuyama

Posted on

10 2

A batch-JS for downloading invoice PDFs from Stripe

I'm running a small business that uses Stripe for accepting payments from users.
While the Stripe dashboard is quite useful, it doesn't provide a quick way to download invoice PDF files for accounting purposes.
So, I wrote a batch script to do so:

import initStripe from 'stripe'
import path from 'path'
import fs from 'fs'
import { exec } from 'child_process'
import moment from 'moment'

const stripe = initStripe('sk_live_****************')

function log(...args) {
  const datetime = moment().format('YYYY-MM-DDTHH:mm:ss')
  console.log.apply(console, [datetime, ...args])
}

async function run() {
  let starting_after = undefined
  let res

  do {
    res = await stripe.invoices.list({
      created: {
        gte: new Date('2020-01-01T00:00:00'),
        lt: new Date('2020-12-31T23:59:59')
      },
      starting_after,
      limit: 10
    })
    const items = res.data
    log('got', items.length, 'items', { starting_after })
    await Promise.all(
      items.map(async (invoice) => {
        try {
          if (invoice.amount_paid <= 0) return
          if (invoice.status !== 'paid') {
            log('Invoice is not paid:', invoice.id, invoice.status)
            return
          }

          log('Processing invoice:', invoice.id)

          const paidAt = new Date(invoice.status_transitions.paid_at * 1000)
          const dest = path.resolve(
            __dirname,
            'invoices',
            '2020',
            moment(paidAt).format('YYYYMMDD-') + invoice.id + '.pdf'
          )
          if (fs.existsSync(dest)) return
          const res = await new Promise((resolve, reject) =>
            exec(
              `/usr/local/bin/wget '${invoice.invoice_pdf}' -O '${dest}'`,
              (err, stdout, _stderr) => {
                err ? reject(err) : resolve(stdout)
              }
            )
          )
          log('Downloaded:', dest, res)
        } catch (e) {
          log(e.stack)
          log('Failed to process invoice:', invoice)
          throw e
        }
      })
    )
    starting_after = items[items.length - 1].id
  } while (res.has_more)
}

run().then(
  function () {
    log('DONE')
  },
  function (err) {
    log('ERROR:', err.stack || err)
    if (err.response) {
      log(err.response)
    }
  }
)
Enter fullscreen mode Exit fullscreen mode

How it works

It retrieves a list of the invoices of the given term by specifying created.gte and created.lt parameters:

    res = await stripe.invoices.list({
      created: {
        gte: new Date('2020-01-01T00:00:00'),
        lt: new Date('2020-12-31T23:59:59')
      },
      starting_after,
      limit: 10
    })
Enter fullscreen mode Exit fullscreen mode

In this example, it retrieves all the invoices issued in 2020.
It only processes the invoices with paid status by checking invoice.status and invoice.amount_paid.
An invoice data has invoice_pdf field, which is a URL to the invoice PDF.
Since downloading a PDF takes time because Stripe generates it on-demand, the script processes up to 10 items at once.
Then, it downloads to ./invoices/2020/. You can change it.

Hope that helps!

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (2)

Collapse
 
luchodamico profile image
Luciano •

Hello! Thanks in advance for this! Im wondering how do i run the script. Im working in macos and tried compiling with node but is not working. Can you guide me so i can test it with my account? Thanks again!

Collapse
 
lafaa profile image
Lafaa •

Bravo!
There were a few adjustments needed to make it work on Windows (especially tricky was understanding I had to remove the single quotes in the wget command), but thank you!