Integrating Stripe

I implemented Stripe into our e-commerce platform at Edinburgh Airport in January 2017 and have learned a lot in the year so I wanted to share some tips, best practices and things to be aware of when moving to Stripe.

Stripe is an online payment processing platform and can be used to take single payments or recurring payments such as monthly subscriptions. Stripe is an end-to-end solution, so all you need to do is provide your bank details and you’re good to go.

Tokens & PCI

In Stripe, tokens are a way of handling payment methods without having to ever see card details. Tokens can be used to either charge a card, or create a customer with a saved card. Tokens can only be charged once, however if you assign the token to a customer, you can charge the customer without requiring the customer to enter their details for every transaction.

Tokens are also used when using other payment methods such as Apple Pay & Google Pay. I’ll touch on this later in the article.

PCI isn’t the most exciting topic, so I’ll put this in early.

There is a lot of miss-information when it comes to PCI, with a lot of people believing that you’re integration isn’t in PCI scope unless you directly handle or store card details. This is incorrect — regardless of your solution, you must validate your PCI compliance annually. Thankfully, Stripe offer a few solutions to make this as easy as possible.

There are many ways to create a token with various levels of PCI requirements. Stripe Checkout and Stripe Elements are the libraries you’ll want to use to collect card details unless you have some exceptional reason to use another method. They both fall into PCI SAQ A, and Stripe can provide you with a Pre-filled SAQ A document.

Many people believe that they can create their own forms and use Stripe.js to generate the tokens, but this actually falls under SAQ A-EP. You will need to fill the assessment out yourself (no Pre-filled document) and it’s way more difficult than SAQ A. Plus, Stripe Checkout & Stripe Elements also give a way better user experience, so I would recommend using them anyway even if PCI wasn’t an issue.

You can (and should) read more about PCI & security with Stripe here:


Ok, now we have our account set up and we can securely get tokens, is time to make some charges!

A charge is the point in which you create the transaction and take the money (unless you want to do a pre-auth, in which case you can set the ‘capture’ argument to ‘false’ and do a manual capture later).

To create a charge, you’re going to need to pass in the token ID which you generated (hopefully with Checkout or Elements) the currency and the amount in which to charge. The amount should be in the smallest currency unit (cents, pence etc… e.g. $10 would be 1000).

You can (but don’t need to) pass in a customer ID to assign the charge to a customer. If you don’t pass a customer ID, the charge will still be successful, just not associated to a customer object. I’ll go in to more detail on this later in the Customer section.

Some tips for charges:

Metadata: You can attach data to a charge as metadata. This can be anything you want. I would recommend saving any data you may want to search by. For example, you could store the booking reference from your eCommerce platform — this would make it easy to find the stripe transaction in the dashboard by booking reference. You could also store referral codes, marketing info etc…

Idempotency Keys: Often on the internet, things go wrong, and often these things happen at the worst time. For example, your customer presses your pay button, Stripe processes the transaction, then wifi drops out. Or, your customers may make a transaction, press back in their browser and manage to somehow attempt to make the transaction again. Idempotency keys are unique IDs which you can pass with your charges. If you pass an idempotency key, Stripe won’t charge the customer again if the charge has already been made but the API will return the same result as if it was the first time attempting the transaction.

There is an awesome blog post on Idempotency Keys which I would encourage you to read:

Additional Fields: When we first went live with Stripe, we noticed declines were slightly higher than we expected. After talking with the awesome support team at Stripe, we added additional parameters (Name and PostCode/Zip Code) when creating the card token. This helped reduce the number of declines by passing the Zip check.


For the first year, we ran on Stripe without using customer objects. We’re now 80% of the way through adding customers and saved cards which is super exciting.

Customer objects allow you to save payment methods (e.g. cards) to a user account. Tokens are generated the same methods as mentioned before, but now you have the ability to save this token to a customer. Once you do this, the token will be replaced with a card ID — you can now use customer ID & card ID to create charges without the user having to re-enter their card details for every transaction.

(This has been addressed. See update below) One tip I would give for customers is if you want to create a charge linked to a customer, but don’t want to save the card to the customer object, you need to:

  1. Add the token to the customer and get the returned card ID
  2. Create the charge using the customer ID and the card ID
  3. Remove the card from the customer object.

This feels a little clunky at the moment — I would like a way of flagging that the card should not be stored, but maybe this is something Stripe will introduce in the future.

Update: I have just been informed that you don’t actually need to follow these 3 steps anymore — it looks like you can now create a charge without passing the customer ID, then update the charge to attach the customer. Thanks @koopajah for the note! More here:


In the dashboard, there is an option to set up webhooks — I would recommend setting these up.

Webhooks post event data to your server so you can maintain a log of everything that has happened on your account. This is really useful when you want to debug, you want real-time reporting, you want to run monitoring to flag any unusual activity or you have other systems that you want to trigger when an event happens.

You can set up webhooks from the API section of the Stripe Dashboard. All you need an accessible endpoint for Stripe to be able to POST to.

Setting up webhooks in the Stripe Dashboard

Your server should return a status of 2xx to let Stripe know the request was successfully received. If any other status code is received, Stripe will try to resend until a 2xx status is finally received.

Note: A redirect status (3xx) will be marked as a failure. You should only respond with a 2xx.

You will want to verify the event received is in fact a valid Stripe webhook, and not a malicious attack. There are a few ways to do this. The webhooks now include a signature and you can either use a Stripe library, or create your own manual verification to verify the webhook is indeed legit.

Another way is to only read the event ID from the webhook, then use the Stripe API to pull the event details. This way, you can be sure you’re not reading any malicious data from the webhook.

Tip: You can get a list of Stripe IP addresses to add to your firewall. I’m not sure how often it changes, but you should always build with the expectation of these IP addresses changing —

Apple Pay & Google Pay

Stripe supports both Apple Pay and now also Google Pay. I’ve only used these on the web, but they work really well.

You can integrate them both by using the ‘Payment Request Button’ method. All this does is check if the customers device is compatible with Apply Pay or if your browser has stored cards (e.g. Chrome with Google Pay). If so, you can use Stripe.js to generate a token which you can pass to your server to create a charge as usual.

This is a super easy integration but adds useful functionality for your users to pay easier.

The one issue I have had with Apple Pay & Google Pay is that there’s currently no easy way to see a list of transactions created with this method. You need to create your own tracking through something like Google Analytics event tracking, Mixpanel, Amplitute etc… I’m sure this will be addressed in the near future however.

You can read more on setting up Apple Pay & Google Pay on the Stripe website:


Overall I’m delighted with our Stripe integration. I’ve used many payment providers in the past but none of them come close to Stripe.

This really is just a brief summary. Stripe has so much more to offer, but these are the main learnings I’ve made in 2017.

If you’re thinking of moving to Stripe, or are curious about starting to take payment for the first time on your site, please feel free to get in touch or leave a comment below with any questions.