25

I'm using the Stripe API and I'd like to present my customer's a list of their invoice history along with the relevant receipts.

I can't find anywhere in the Stripe API (https://stripe.com/docs/api?lang=php) that allows me fetch a list of a customer's receipts. Is there something I'm missing?

Chris Bowal
  • 381
  • 4
  • 9
  • I'm trying to achieve the same thing. Asking in the #stripe IRC channel, I was told there isn't a way to retrieve the email receipt ID. :\ – excid3 Oct 30 '14 at 20:26

4 Answers4

2

Each invoice includes a charge property which contains the id of its last charge. This will either be the current/final payment attempt (for invoices not successfully paid) or the successful payment (for paid invoices).

This allows you to easily use the charge and invoice data to present a receipt to the user, but a "receipt" is itself more of an application-side notion; its needs and presentation vary with the application.

Once you've got the data, you can present a receipt however you like.

Ideally, I recommend caching these records locally. It's almost painless to do if you're receiving webhooks. You can then model (and search!) a local receipt record as best fits your needs, your customer then gets the benefit of very fast billing display, and we all get the benefit of less load on Stripe's API endpoints.

colinm
  • 4,258
  • 24
  • 19
  • 24
    Sure, that's a good way to go about it if you have a few days to spend. However, Stripe is very much about fast and simple integration, and this is certainly neither fast nor simple. Considering that Stripe already offers [email receipts](https://support.stripe.com/questions/does-stripe-offer-email-receipts) and you can preview those in the dashboard as well, I think it's reasonable to ask whether there's a way to retrieve exactly those receipts from the API. (I also haven't found a way to do so yet.) – Henrik Heimbuerger Oct 20 '14 at 13:09
2

I was able to do this in a slightly hacky way in Java and the Apache IO / Lang libraries.

NOTE - this solution is in Java but the general idea should work easily in any other language.

I added the following to my pom.xml file: -

  <dependencies>

    <dependency>
      <groupId>com.stripe</groupId>
      <artifactId>stripe-java</artifactId>
      <version>19.24.0</version>
    </dependency>

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.10.0</version>
    </dependency>

    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.12.0</version>
    </dependency>

    ...

  </dependencies>

The steps were as follows: -

  1. Use Stripe API to return a list of charge objects (ref https://stripe.com/docs/api/charges/list).
  2. Iterate over each charge object and take a note of the receipt_url (ref https://stripe.com/docs/api/charges/object).
  3. Download receipt page (HTML) to a String e.g. using IOUtils.toString
  4. Extract the receipt download url (this contains invrc_xxx e.g. https://dashboard.stripe.com/emails/receipts/invrc_NmIZClQPPEELg1J0QvNJ6sJQ/pdf). I used a basic StringUtils.substringBetween call to extract this.

    NOTE: converting the HTML page to XML and extracting this via an XPath would be more professional.

  5. Download this URL locally as a PDF using e.g. FileUtils.copyURLToFile.

The code is as follows: -

import com.stripe.Stripe;
import com.stripe.model.Charge;
import com.stripe.model.ChargeCollection;
import com.stripe.param.ChargeListParams;

import java.io.File;
import java.net.URL;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

public class StripeReceiptDownloader {

    public static void main(String[] args) throws Exception {
        if (args.length != 1) {
            System.out.println("Missing Stripe API key");
            System.exit(-1);
        }
        Stripe.apiKey = args[0];

        File downloadFolder = new File("stripe-receipts");

        // Return a list of charges and loop through each
        ChargeCollection charges = Charge.list(ChargeListParams.builder().setLimit(3L).build());
        for (Charge charge : charges.getData()) {

            // Download HTML page from receipt_url in charge object
            String receiptPageContents = IOUtils.toString(new URL(charge.getReceiptUrl()));

            // Extract invcrc ID 
            String invrcId = StringUtils.substringBetween(receiptPageContents, "receipts/invoices", "/pdf");
            String receiptPdfDownload = "https://dashboard.stripe.com/receipts/invoices" + invrcId + "/pdf";

            String filename = invrcId + ".pdf";   // you could also use fields from charge object to give better context to filename
            File receiptFile = new File(downloadFolder, filename);

            System.out.println("Downloading [ " + receiptPdfDownload + " ] to [ " + receiptFile + " ]");
            FileUtils.copyURLToFile(new URL(receiptPdfDownload), receiptFile);
        }
    }

}

This will download the receipts to the specified folder and output something like the following: -

Downloading [ https://dashboard.stripe.com/emails/receipts/invrc_1J2lQPQvELg6sNJNmIZECPJQ/pdf ] to [ stripe-receipts\1J2lQPQvELg6sNJNmIZECPJQ.pdf ]
Downloading [ https://dashboard.stripe.com/emails/receipts/invrc_1ItqEg6L62JELNmIZDMzBrY7/pdf ] to [ stripe-receipts\1ItqEg6L62JELNmIZDMzBrY7.pdf ]
Downloading [ https://dashboard.stripe.com/emails/receipts/invrc_1IzmM1aJNIZ6fTEELgt07wYW/pdf ] to [ stripe-receipts\1IzmM1aJNIZ6fTEELgt07wYW.pdf ]
bobmarksie
  • 3,282
  • 1
  • 41
  • 54
1

It really wouldn't be too hard. First you would get all invoices:

https://stripe.com/docs/api?lang=php#invoice_object https://stripe.com/docs/api?lang=php#list_customer_invoices

Each invoice has a "customer" property, so all you need to do is search through them for the invoice that has a customer id that matches yours.

Each invoice has a "receipt_number" property, so you should be good to go!

urban_raccoons
  • 3,499
  • 1
  • 22
  • 33
  • 3
    unfortunately the 'receipt_number' refers to the receipt code (ie. 2535-2928) not the receipt_id (ie. invrc_14t8HA2ndNH5cEQ) – Chris Bowal Oct 30 '14 at 02:10
  • Can you point me to anywhere that the receipt_id exists? And what exactly do you want to be able to present to the customer? – urban_raccoons Oct 30 '14 at 19:30
  • 3
    If you visit a charge on Stripe's dashboard and click "View Receipt" there is a permalink to the receipt there. That's what he's looking for I believe, I am too. – excid3 Oct 30 '14 at 20:24
  • 6
    But as far as I know, there's no way to retrieve the `invrc_XXXX` ID from anywhere except the url there. – excid3 Oct 30 '14 at 20:33
0

I really like the answer given by colinm, and I want to expand on both the why and how, because I think it's a great answer but it could be fleshed out in a little more detail. Interestingly I think all three answers could be combined here, like, I wouldn't do just one of these things, I would do all three.

I think the most sustainable practice here is to replicate the relevant data locally, in your own database. This has several advantages, notably:

  • Performance - There is no need to send a request to an external box. This will make your scripts execute much faster.
  • Reduced Server Load - When you query the Stripe API, they typically send back large objects. I've had Stripe return objects taking up about 40k in memory, when I only need a single value, such as an integer. But, depending on what language you're using, merely loading the file for the Stripe API can be a much bigger burder. For example, in PHP, jsut loading the libraries and doing a single call will make a script take up an additional 1MB RAM, and scripts that require the response from an external server will typically stay in memory much longer than a typical script. If you're allowing end users (and not just admins) to load scripts that make calls to the Stripe API, this problem is magnified. Best practice is to not ever allow users to trigger interaction with the Stripe API any more than absolutely necessary (i.e. only when they are doing something Stripe needs to know about.)
  • Uptime - If Stripe has any downtime, or if there is any trouble with connectivity between your server and stripe, your information is still available and there is no visible service interruption to your users.
  • Features - This is what you care about here, and what is ultimately driving you to need a local database. You can structure the data how you want, which includes possibilities like putting indices on whatever fields you want so that you can quickly and efficiently return whatever information you want in a query. You are not limited by what Stripe allows you to do with their API.
  • Extensibility - If you ever want to change payment processors, you can seamlessly switch over to a new one without users even noticing, because you have abstracted your own database and records of invoicing from your payment processor. In fact, if you want, you could even have multiple payment processors at the same time, displayed to your users in a unified invoicing system. Stripe is pretty fantastic right now in a lot of ways, but who knows where the company is going in the long-run. Sometimes once-excellent companies and their products fall from grace. Maybe a better competitor will come along. And there are already a few payment methods that it doesn't support but some of its competitors do: if you end up expanding into a market where one of those payment methods is preferred, you might need another payment processor.

The more you think about it, the more you realize that it's not only best practice to store this information locally, it's a huge benefit, and it's a bit of a risk not to do it.

How to get this started?

First, create in your own database, the relevant tables and structure for the events you want to store.

Using webhooks, whenever a relevant event happens, capture the event, extract the relevant data from it, and store it locally in your database. For invoicing, you will need to capture any event that could potentially reflect a change in the invoice.

You do not, however, have to store all or even most of the data in each event. Stripe stores a huge amount of data in each event, and in practice you need very little of it. I can't say exactly what you need for your use; this depends on what information you want to store, which will depend both on what you want to present to your users, and whether you want to store any additional information behind-the-scenes for your own internal use and recordkeeping.

How to catch-up if you haven't done this from the start?

In this case, you're going to need to iterate through all the records and extract the relevant information.

This is where the answers from bobmarksie and urban_raccoons come in. They provide two suggestions of two completely different ways to do it, bobmarksie suggests iterating through receipts and urban_raccoons suggests doing it by invoices. The solution by bobmarksie gives details using Java, but you can do it in any language.

Regardless of how you carry out the details, I recommend combining both approaches: iterate through all invoices, and all recepits and link them up in your database. Now you'll have a complete, up-to-date listing, and you can rely on webhooks to update your local database in the long-run.

cazort
  • 516
  • 6
  • 19