A batch-JS for downloading invoice PDFs from Stripe
Tags: stripe, javascript, accounting
Published: 2021-04-07 11:33:31

I'm running [a small business](https://www.inkdrop.app/) 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:

```js
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)
    }
  }
)
```

## How it works

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

```js
    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
    })
```

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!