This is a follow-up to my introductory post on Stripe. I covered Stripe’s merchant and marketplace products in the first post, and in this one we’ll try building some basic web apps that use Stripe Checkout and Stripe.js.

Note that to keep the focus on the API I kept things as minimal as possible, which meant omitting most error checking, so do not use any of the code from this post as-is in production. At the very least, you need to add comprehensive error handling and use HTTPS for both the frontend and the backend.

Backend: Node.js + Express

We’ll use a common node.js + Express backend for all the examples, so let’s cover that first.

Making a charge against a credit/debit card using the Stripe API requires a surprisingly small amount of code. The following is a fully-functional Node.js/Express app that will make a $10 charge against a card token supplied in an HTTP POST request to http://<server>:3000/charge , and respond with either an HTTP 204 OK or an HTTP 500 error depending on whether the card was successfully charged or not.

var express = require('express'); var bodyParser = require('body-parser'); var stripe = require('stripe')('sk_MY_SECRET_KEY'); var app = express(); app.use(bodyParser()); app.post('/charge', function(req, res) { var stripeToken = req.body.stripeToken; var amount = 1000; stripe.charges.create({ card: stripeToken, currency: 'usd', amount: amount }, function(err, charge) { if (err) { res.send(500, err); } else { res.send(204); } }); }); app.use(express.static(__dirname)); app.listen(process.env.PORT || 3000); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 var express = require ( 'express' ) ; var bodyParser = require ( 'body-parser' ) ; var stripe = require ( 'stripe' ) ( 'sk_MY_SECRET_KEY' ) ; var app = express ( ) ; app . use ( bodyParser ( ) ) ; app . post ( '/charge' , function ( req , res ) { var stripeToken = req . body . stripeToken ; var amount = 1000 ; stripe . charges . create ( { card : stripeToken , currency : 'usd' , amount : amount } , function ( err , charge ) { if ( err ) { res . send ( 500 , err ) ; } else { res . send ( 204 ) ; } } ) ; } ) ; app . use ( express . static ( __dirname ) ) ; app . listen ( process . env . PORT || 3000 ) ;

To test, save the above code into a file called index.js , replacing sk_MY_SECRET_KEY with your Stripe secret key (if you don’t have one, sign up for an account with Stripe). Then setup and run it like you would any Express application, i.e.:

npm init npm install --save stripe express body-parser node index.js 1 2 3 npm init npm install -- save stripe express body - parser node index .js

Your backend is now running at http://localhost:3000

This backend can accept a Stripe card token and make a $10 charge against it. Sweet! We now need to build a frontend that accepts card information, converts that into a card token, and sends it to the backend.



Frontend: Stripe Checkout

1. Minimal Checkout example

<!doctype html> <html lang=en> <head> <meta charset="utf-8"> <title>Stripe example</title> </head> <body> <form action="/charge" method="POST"> <script src="https://checkout.stripe.com/checkout.js" class="stripe-button" data-key="pk_MY_PUBLISHABLE_KEY"> </script> </form> </body> </html> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <!doctype html> <html lang = en > <head> <meta charset = "utf-8" > <title> Stripe example </title> </head> <body> <form action = "/charge" method = "POST" > <script src = "https://checkout.stripe.com/checkout.js" class = "stripe-button" data-key = "pk_MY_PUBLISHABLE_KEY" > </script> </form> </body> </html>

Save the above into a file called stripe.html in the same directory you saved the backend index.js file into, replacing pk_MY_PUBLISHABLE_KEY with your Stripe publishable key. Open the application by visiting http://localhost:3000/stripe.html

Click on the “Pay with Card” button to launch the Stripe Checkout UI and enter email and card information. You can use any valid email, expiry date and CVC, and one of the test card numbers listed here. I usually use a@b.com, 01/20, 123 and 4242 4242 4242 4242, respectively.

When you hit Pay, the card number you entered will be charged $10. Pretty amazing that it’s this easy to accept card payments!

2. Customizing the Checkout dialog

Stripe Checkout is actually pretty configurable. The previous example used the absolute minimum possible configuration (just the data-key parameter), so let’s go ahead and customize the dialog a little:

Show the site logo

Show the site name

Show a description for the charge

Show the charge amount

Ask for the billing address

Change the ‘Pay with Card’ button label

<form action="/charge" method="POST"> <script src="https://checkout.stripe.com/checkout.js" class="stripe-button" data-key="pk_MY_PUBLISHABLE_KEY" data-image="https://nairteashop.org/wp-content/uploads/avatar.png" data-name="nairteashop.org" data-description="Send lots of love" data-amount="1000" data-billing-address="true" data-label="Dolla dolla bill y'all" > </script> </form> 1 2 3 4 5 6 7 8 9 10 11 12 <form action = "/charge" method = "POST" > <script src = "https://checkout.stripe.com/checkout.js" class = "stripe-button" data-key = "pk_MY_PUBLISHABLE_KEY" data-image = "https://nairteashop.org/wp-content/uploads/avatar.png" data-name = "nairteashop.org" data-description = "Send lots of love" data-amount = "1000" data-billing-address = "true" data-label = "Dolla dolla bill y'all" > </script> </form>

Replace the contents of <body> in stripe.html from the first example with the above code, replace pk_MY_PUBLISHABLE_KEY with your Stripe publishable key, then refresh the page to see the updated button and dialog.

The full list of configuration parameters supported by Checkout is available here.

3. Launching the Checkout dialog programmatically

In the above examples, the Checkout dialog is always launched using a Stripe-generated button. We customized the button label in the second example, but there may be cases when we need to customize the look of the button further, or perhaps launch the dialog from a drop-down menu or link.

To do this, we need to launch the Checkout dialog via Javascript.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script src="https://checkout.stripe.com/checkout.js"></script> <a id="pay" href="#">Dolla dolla bill y'all</a> <script> // Define handler to be called when Stripe returns a card token function onReceiveToken(token, args) { // Submit token to server so it can charge the card $.ajax({ url: '/charge', type: 'POST', data: { stripeToken: token.id } }); } // Configure Checkout var checkout = StripeCheckout.configure({ key: 'pk_MY_PUBLISHABLE_KEY', token: onReceiveToken, image: 'https://nairteashop.org/wp-content/uploads/avatar.png', name: 'nairteashop.org', description: 'Send lots of love', amount: 1000, billingAddress: 'true' }); // Open Checkout when the link is clicked $('#pay').on('click', function() { checkout.open(); return false; }); </script> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <script src = "//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" > </script> <script src = "https://checkout.stripe.com/checkout.js" > </script> <a id = "pay" href = "#" > Dolla dolla bill y'all </a> <script> // Define handler to be called when Stripe returns a card token function onReceiveToken ( token , args ) { // Submit token to server so it can charge the card $ . ajax ( { url : '/charge' , type : 'POST' , data : { stripeToken : token . id } } ) ; } // Configure Checkout var checkout = StripeCheckout . configure ( { key : 'pk_MY_PUBLISHABLE_KEY' , token : onReceiveToken , image : 'https://nairteashop.org/wp-content/uploads/avatar.png' , name : 'nairteashop.org' , description : 'Send lots of love' , amount : 1000 , billingAddress : 'true' } ) ; // Open Checkout when the link is clicked $ ( '#pay' ) . on ( 'click' , function ( ) { checkout . open ( ) ; return false ; } ) ; </script>

Same drill as before. Replace the contents of <body> in stripe.html with the above, plug in your Stripe key and refresh the page. This time, instead of the usual blue Stripe button you will see a link. Clicking on the link will bring up the Checkout dialog.

The first section of the code is a function that submits data to the server once the card token is received from Stripe. The second section configures the Checkout dialog similarly to how we did it in the previous example, but with Javascript. The third section takes care of opening the Checkout dialog when the link is clicked.

The code is a bit longer in this case because the logic in the first and third sections were handled by Stripe Checkout in the first two examples, albeit at the cost of customizability.

Frontend: Stripe.js

Let’s continue on our customization spree. Now that we have our own UI element that launches the Checkout dialog, let’s see if we can use our own UI elements to replace the Checkout dialog itself. Perhaps the look & feel of the dialog doesn’t match the rest of our site, or we want to remove some of the fields (like email), or we want to add additional UI elements. To accomplish this, we’ll have to go one level down to Stripe.js.

Stripe.js encapsulates the card information to token mapping functionality that is part of Checkout. By linking our custom UI code with Stripe.js, we can mimic the end-to-end functionality of Checkout.

1. Minimal Stripe.js example

Let’s start with a super-minimal example: a bare-bones form that takes card information from the user, uses Stripe.js to securely transmit it to Stripe to get back a card token, and then finally submits the form to the server along with the token so the card can be charged.

<form id="form" action="/charge" method="POST"> <!-- Card information --> <label>Card #: <input type="text" size="16" data-stripe="number" placeholder="Card number" /></label> <label>Expiry month: <input type="text" size="2" data-stripe="exp-month" placeholder="MM" /></label> <label>year: <input type="text" size="2" data-stripe="exp-year" placeholder="YY" /></label> <label>CVC: <input type="text" size="4" data-stripe="cvc" placeholder="CVC" /></label> <!-- Submit button --> <button type="submit">Pay</button> </form> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script src="https://js.stripe.com/v2/"></script> <script type="text/javascript"> Stripe.setPublishableKey('pk_MY_PUBLISHABLE_KEY'); var $form = $('#form'); $form.on('submit', function() { // First submit the card information to Stripe to get back a token Stripe.card.createToken($form, function(status, response) { var token = response.id; // Save the token into a hidden input field $form.append($('<input type="hidden" name="stripeToken" />').val(token)); // Now submit the form to our server so it can make the charge against the token $form.get(0).submit(); }); return false; }); </script> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 <form id = "form" action = "/charge" method = "POST" > <!-- Card information --> <label> Card #: <input type = "text" size = "16" data-stripe = "number" placeholder = "Card number" /> </label> <label> Expiry month: <input type = "text" size = "2" data-stripe = "exp-month" placeholder = "MM" /> </label> <label> year: <input type = "text" size = "2" data-stripe = "exp-year" placeholder = "YY" /> </label> <label> CVC: <input type = "text" size = "4" data-stripe = "cvc" placeholder = "CVC" /> </label> <!-- Submit button --> <button type = "submit" > Pay </button> </form> <script src = "//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" > </script> <script src = "https://js.stripe.com/v2/" > </script> <script type = "text/javascript" > Stripe . setPublishableKey ( 'pk_MY_PUBLISHABLE_KEY' ) ; var $ form = $ ( '#form' ) ; $ form . on ( 'submit' , function ( ) { // First submit the card information to Stripe to get back a token Stripe . card . createToken ( $ form , function ( status , response ) { var token = response . id ; // Save the token into a hidden input field $ form . append ( $ ( '<input type="hidden" name="stripeToken" />' ) . val ( token ) ) ; // Now submit the form to our server so it can make the charge against the token $ form . get ( 0 ) . submit ( ) ; } ) ; return false ; } ) ; </script>

Although this is functional, I felt icky just typing fake card numbers into this UI. Let’s see if we can make the UI look a little better.

2. Using a nicer Bootstrap-based dialog

Let’s glam up the form a little using the Bootstrap library. First, add the following to the <head> section of stripe.html :

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css"> <style> body { margin: 8px; } .modal-dialog { width: 350px; } .modal-header { border: none; padding: 0; } .modal-content { padding: 10px; } </style> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <link rel = "stylesheet" href = "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" > <link rel = "stylesheet" href = "//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css" > <link rel = "stylesheet" href = "//netdna.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css" > <style> body { margin : 8px ; } .modal-dialog { width : 350px ; } .modal-header { border : none ; padding : 0 ; } .modal-content { padding : 10px ; } </style>

Now replace the <body> contents with the following:

<button class="btn btn-primary" data-toggle="modal" data-target="#checkout">Dolla dolla bill y'all</button> <div class="modal fade" id="checkout"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal">×</button> </div> <div class="modal-body"> <form id="form" action="/charge" method="POST" class="form-horizontal"> <div class="form-group"> <div class="col-sm-12"> <div class="input-group"> <span class="input-group-addon"><span class="glyphicon glyphicon-credit-card"></span></span> <input id="card-num" class="form-control" type="text" size="16" placeholder="Card number" autofocus="autofocus" /> </div> </div> </div> <div class="form-group"> <div class="col-sm-6"> <div class="input-group"> <span class="input-group-addon"><span class="glyphicon glyphicon-calendar"></span></span> <input id="card-exp" class="form-control" type="text" size="5" placeholder="MM/YY" /> </div> </div> <div class="col-sm-6"> <div class="input-group"> <span class="input-group-addon"><span class="glyphicon glyphicon-lock"></span></span> <input id="card-cvc" class="form-control" type="text" size="4" placeholder="CVC" /> </div> </div> </div> </form> </div> <div class="modal-footer"> <button id="submit" type="button" class="btn btn-primary col-sm-12" data-progress-text="<span class='glyphicon glyphicon-refresh fa-spin'></span>" data-success-text="<span class='glyphicon glyphicon-ok'></span>" > Pay </button> </div> </div> </div> </div> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <script src="https://js.stripe.com/v2/"></script> <script src="//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script> <script type="text/javascript"> Stripe.setPublishableKey('pk_MY_PUBLISHABLE_KEY'); var $btn = $('#submit'); $btn.on('click', function() { $btn.prop('disabled', true); $btn.button('progress'); var cardNum = $('#card-num').val(); var cardExp = $('#card-exp').val().split('/'); var cardCVC = $('#card-cvc').val(); // First submit the card information to Stripe to get back a token Stripe.card.createToken({ number: cardNum, exp_month: cardExp[0], exp_year: cardExp[1], cvc: cardCVC }, function(status, response) { var $form = $('#form'); var token = response.id; // Save the token into a hidden input field $form.append($('<input type="hidden" name="stripeToken" />').val(token)); // Now submit the form to our server so it can make the charge against the token $form.get(0).submit(); // All done! $btn.addClass('btn-success').removeClass('btn-primary'); $btn.button('success'); setTimeout(function() { $('#checkout').modal('hide'); }, 250); }); return false; }); </script> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 <button class = "btn btn-primary" data-toggle = "modal" data-target = "#checkout" > Dolla dolla bill y'all </button> <div class = "modal fade" id = "checkout" > <div class = "modal-dialog" > <div class = "modal-content" > <div class = "modal-header" > <button type = "button" class = "close" data-dismiss = "modal" > × </button> </div> <div class = "modal-body" > <form id = "form" action = "/charge" method = "POST" class = "form-horizontal" > <div class = "form-group" > <div class = "col-sm-12" > <div class = "input-group" > <span class = "input-group-addon" > <span class = "glyphicon glyphicon-credit-card" > </span> </span> <input id = "card-num" class = "form-control" type = "text" size = "16" placeholder = "Card number" autofocus = "autofocus" /> </div> </div> </div> <div class = "form-group" > <div class = "col-sm-6" > <div class = "input-group" > <span class = "input-group-addon" > <span class = "glyphicon glyphicon-calendar" > </span> </span> <input id = "card-exp" class = "form-control" type = "text" size = "5" placeholder = "MM/YY" /> </div> </div> <div class = "col-sm-6" > <div class = "input-group" > <span class = "input-group-addon" > <span class = "glyphicon glyphicon-lock" > </span> </span> <input id = "card-cvc" class = "form-control" type = "text" size = "4" placeholder = "CVC" /> </div> </div> </div> </form> </div> <div class = "modal-footer" > <button id = "submit" type = "button" class = "btn btn-primary col-sm-12" data-progress-text = "<span class='glyphicon glyphicon-refresh fa-spin'></span>" data-success-text = "<span class='glyphicon glyphicon-ok'></span>" > Pay </button> </div> </div> </div> </div> <script src = "//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" > </script> <script src = "https://js.stripe.com/v2/" > </script> <script src = "//netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" > </script> <script type = "text/javascript" > Stripe . setPublishableKey ( 'pk_MY_PUBLISHABLE_KEY' ) ; var $ btn = $ ( '#submit' ) ; $ btn . on ( 'click' , function ( ) { $ btn . prop ( 'disabled' , true ) ; $ btn . button ( 'progress' ) ; var cardNum = $ ( '#card-num' ) . val ( ) ; var cardExp = $ ( '#card-exp' ) . val ( ) . split ( '/' ) ; var cardCVC = $ ( '#card-cvc' ) . val ( ) ; // First submit the card information to Stripe to get back a token Stripe . card . createToken ( { number : cardNum , exp_month : cardExp [ 0 ] , exp_year : cardExp [ 1 ] , cvc : cardCVC } , function ( status , response ) { var $ form = $ ( '#form' ) ; var token = response . id ; // Save the token into a hidden input field $ form . append ( $ ( '<input type="hidden" name="stripeToken" />' ) . val ( token ) ) ; // Now submit the form to our server so it can make the charge against the token $ form . get ( 0 ) . submit ( ) ; // All done! $ btn . addClass ( 'btn-success' ) . removeClass ( 'btn-primary' ) ; $ btn . button ( 'success' ) ; setTimeout ( function ( ) { $ ( '#checkout' ) . modal ( 'hide' ) ; } , 250 ) ; } ) ; return false ; } ) ; </script>

Now when you press the button, you should see a modal dialog that looks like this:



Still very bare-bones, especially compared to Stripe Checkout, but nonetheless decent looking and a good base to build on.

And that concludes my high-level walkthrough of Stripe Checkout and Stripe.js integration. Hopefully you found it informative!