This is going to be a super quick tutorial on how to accept payments with Stripe payment processor and node.js. At Browserling we're moving to Stripe right this very moment so I thought I'd write this quick post. Stripe is the most incredible payment processor - it took me like 30 minutes to figure everything out. Everything is well documented and works like a charm!

First, you will need the node-stripe module. Install it through npm, as always:

npm install stripe

Next, you'll need to login into Stripe, and setup a plan:


Setting up a new Stripe plan.

Next, you'll need to find the test and live keys that are used in the payment code. They are located in Account Settings -> API Keys.


Stripe keys are located in Account Settings -> API keys.

Next, you'll need to include Stripe's JavaScript library in your HTML code:

<script type="text/javascript" src="https://js.stripe.com/v1/"></script>

Next, you'll need to setup an HTML form with card name, cvc, expiration date, amount (in cents!). You don't need to ask the name or address, that stuff is old school:

<div id="stripe-form">
  <form action="/plans/browserling_developer" method="POST" id="payment-form">
    <div class="form-row">
      <div class="cc-text">Card Number</div>
      <input type="text" size="30" autocomplete="off" class="card-number"/>
    </div>
    <div class="form-row">
      <div class="cc-text">CVC</div>
      <input type="text" size="4" autocomplete="off" class="card-cvc"/>
    </div>
    <div class="form-row">
      <div class="cc-text">Expiration (MM/YYYY)</div>
      <input type="text" size="2" class="card-expiry-month"/>
      <span> / </span>
      <input type="text" size="4" class="card-expiry-year"/>
    </div>
    <input type="hidden" name="amount" value="2000" id="cc-amount">
    <button type="submit" class="submit-button">Submit Payment</button>
  </form>
</div>
<div id="error" class="hidden"></div>
<div id="success" class="hidden">Thanks for signing up at Browserling!</div>

Next, you'll need to generate a token when the form gets submitted, and submit it to your node.js application, instead of submitting credit card number and other info:

var publicStripeApiKey = '...';
var publicStripeApiKeyTesting = '...';

Stripe.setPublishableKey(publicStripeApiKey);

function stripeResponseHandler (status, response) {
  if (response.error) {
    $('#error').text(response.error.message);
    $('#error').slideDown(300);
    $('#stripe-form .submit-button').removeAttr("disabled");
    return;
  }
  
  var form = $("#payment-form");
  form.append("<input type='hidden' name='stripeToken' value='" + response.id + "'/>");

  $.post(
    form.attr('action'),
    form.serialize(),
    function (status) {
      if (status != 'ok') {
        $('#error').text(status);
        $('#error').slideDown(300);
      }
      else {
        $('#error').hide();
        $('#success').slideDown(300);
      }
      $('.submit-button').removeAttr("disabled");
    }
  );
}

// http://stripe.com/docs/tutorials/forms
$("#payment-form").submit(function(event) {
  $('#error').hide();
  // disable the submit button to prevent repeated clicks
  $('.submit-button').attr("disabled", "disabled");

  var amount = $('#cc-amount').val(); // amount you want to charge in cents
  Stripe.createToken({
    number: $('.card-number').val(),
    cvc: $('.card-cvc').val(),
    exp_month: $('.card-expiry-month').val(),
    exp_year: $('.card-expiry-year').val()
  }, amount, stripeResponseHandler);

  // prevent the form from submitting with the default action
  return false;
});

Next, you need to setup a route handler in node.js web server for all your plan names. In this tutorial I'll handle just browserling_developer plan:

var express = require('express');

var stripeApiKey = "...";
var stripeApiKeyTesting = "..."
var stripe = require('stripe')(stripeApiKey);

app = express.createServer(express.bodyDecoder);

app.post("/plans/browserling_developer", function(req, res) {
  stripe.customers.create({
    card : req.body.stripeToken,
    email : "...", // customer's email (get it from db or session)
    plan : "browserling_developer"
  }, function (err, customer) {
    if (err) {
      var msg = customer.error.message || "unknown";
      res.send("Error while processing your payment: " + msg;
    }
    else {
      var id = customer.id;
      console.log('Success! Customer with Stripe ID ' + id + ' just signed up!');
      // save this customer to your database here!
      res.send('ok');
    }
  });
});

That's it! This simple node.js code handles POST requests to /plans/browserling_developer, and creates a new customer at Stripe. Notice that it uses req.body.stripeToken and doesn't even touch credit card info.

I have never worked with a payment processor which was easier to setup. It's a pure pleasure to use Stripe!

Comments

December 29, 2011, 17:11

For the love of god and all things holy, please cache your jquery selectors.

var error = $('#error');

December 30, 2011, 07:00

Ah, it doesn't seem like such a sin in this case. Those selectors are just by ID, which will always be fast.

Thanks for the stripe Peteris! Very handy.

December 30, 2011, 14:02

You're welcome! And you're right about the selectors. Steve's comment is pretty silly.

December 29, 2011, 22:09

In this line:
// prevent the form from submitting with the default action
return false;

If you want to post to the server you need to comment this line, Right?

BTW, Good article.

December 30, 2011, 02:58

stripeResponseHandler() posts to the server with AJAX.

January 02, 2012, 04:43

Stripe seems pretty scary. One typo, e.g. forget to return false from the submit handler, and poof your credit card data is sent in the clear to an unsecured server. It would be far better if your credit card was entered in a separate pop-up window hosted on stripe or even better if there was something like Facebook connect for credit card companies so you cc num never is typed into a 3rd party site.

Ryan LaBarre Permalink
February 14, 2012, 20:55

The stripe.js file is loaded in via an https server, and presumably anyone implementing this will be smart enough to only host their own server-side calls via https as well.

Anywhere you input your credit card number in a form, you are putting trust the domain actually hosting that form to be following a few basic steps like this -- you can't blame the processing library (stripe, paypal, whatever) for naively insecure (or malicious) implementations by an end-user (read: unknown new e-commerce website). That happens with every payment processing library somewhere in the world at some point, it's up to users to realize the site is a scam (regardless of their supposed use of a credible payment processor).

This actually looks like a pretty foolproof system, it'd be hard to inadvertently share a customer's information using a procedure like this, even when trying to purposely mess up the implementation step in common JS ways. The only things the server-side code could potentially share inadvertently are the customer's email address, and an encrypted identification token. And assuming this is all via https, even those are still encrypted.

Peter Balogh Permalink
May 04, 2012, 17:26

The thing is, I don't see anything the example code above to indicate that this is hosting any part of the app (the form or the node.js server app) via https. Am I missing something?

The node.js code doesn't reference any .pem files. Was this left out for the sake of concision? Or if not, how is this an https server?

jake Permalink
May 19, 2012, 22:26

The entire stripe library is loaded in via https:// and all AJAX calls are done vai https://. in other words, stripe.js is entirely secure. The only risk you have of loosing ANYTHING is the token that stripe returns, which is useless unless you have the secret key (which is secret and stored server-side)..

Leonardo Alves Permalink
January 24, 2013, 18:15

Now they have stripe buttons. Which opens a pop up with a form hosted by stripe to create the token. Them you do whatever you want with the token. No need to handle credit card info yourself.

Jason Kostempski Permalink
January 05, 2012, 16:15

"You don't need to ask the name or address, that stuff is old school"

Can you provide some sources on this idea? I'd like to research it.

Chris Bumgardner Permalink
April 11, 2012, 09:39

I just started on integrating stripe & node myself, and found the docs (https://stripe.com/docs/stripe.js#createToken). They don't go into much detail on why these fields are optional, but they seem to confirm the original assertion:

"The following fields are entirely optional — they cannot result in a token creation failing:
name: cardholder name.
address_line1: billing address line 1.
address_line2: billing address line 2.
address_state: billing address state.
address_zip: billing zip as a string, e.g. '94301'.
address_country: billing address country."

thick Permalink
June 11, 2012, 09:05

It'd maybe be smart to clear the form before posting it back to your own server (if you're putting node behind a proxy with request logging). And for that matter, you could also append the submit button to the form via JS so that a user won't post it directly to your server if they happen to have JS turned off... After all, the point of everything Stripe's doing is to AVOID posting sensitive data to (potentially) insecure servers.

weiquan Permalink
December 02, 2013, 02:56

our project has the same requirement as yours. Need one page for user to submit credit card information, then submitted to the server side node js. could you provide your source code on this feature?

Thanks

November 19, 2014, 21:14

Terima kasih informasinya gan :D

http://goo.gl/lNMX3D

November 19, 2014, 21:16

Terima kasih atas artikel yang sangat bermanfaat ini =))

http://goo.gl/YyhwYt

Leave a new comment

(why do I need your e-mail?)

(Your twitter name, if you have one. (I'm @pkrumins, btw.))

Type the word "security": (just to make sure you're a human)

Please preview the comment before submitting to make sure it's OK.

Advertisements