Writing the JavaScript Code for Handling Stripe Payments

December 5, 2012 — 20 Comments
This entry is part 5 of 8 in the series Processing Payments with Stripe

In my previous post in this series, I covered how you create an HTML form for securely handling payments via Stripe. As explained in that post, thanks to the Stripe.js library, the proper HTML, and a bit of JavaScript, you can easily and securely handle payments on your site without getting mired in the PCI compliance muck. The secret is the Stripe.js library: it sends the customer’s payment information from the client to Stripe’s server and returns a token that Stripe associated with that payment information. Then, when the form is submitted, the token can be used by the PHP on your site to actually process the payment. The customer’s payment information, however, never touches your server. You get paid and the customer is protected.

In this post, I’ll walk through the necessary JavaScript to handle the client-side of that process. Note that this article assumes that you have read the previous article. And comfort with JavaScript and jQuery is required, too.

Recapping the Process

As previously explained, the Stripe payment process (when using the Stripe.js JavaScript library) works like so:

  1. The customer loads an HTML form on your site. Let’s call that page buy.php.
  2. The form takes the requisite payment information: credit card number, expiration month and year, CVC, customer name, etc.
  3. The form does not use name attributes for the payment fields! This keeps the customer data from reaching your server (and therefore saving you lots of security headaches).
  4. When the form is submitted, the payment information needs to be sent to Stripe via Ajax (i.e., JavaScript). This means that JavaScript must prevent the form’s actual submission.
  5. Stripe will return a string of characters, called a token, that represents the payment information (assuming the payment information was valid).
  6. The JavaScript that handles the Ajax request needs to store that token in the form as a hidden element. This makes the token available to the server-side code (the PHP) when the form is actually submitted.
  7. The JavaScript that handles the Ajax request also needs to let the form submission go through (assuming there were no errors).
  8. If any errors occurred, the JavaScript should report upon those and not submit the form.
  9. When the form is submitted to the server, the server-side script will use the token to actually request that the payment be processed.

Steps 1-3 were discussed in the previous post. In this post, I’ll provide and explain the code for Steps 4-8. In the next post, I’ll address Step 9.

The JavaScript Scripts

My recommendation is to put all the required JavaScript code in two or three SCRIPT tags. First, you must include the Stripe.js library. It’s served from Stripe’s own servers:

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

Note that this should go in the HEAD of your HTML page. Also, for performance reasons, only the page on your site that actually accepts payments should include all this JavaScript (in other words, don’t just put this into the header and footer files so it’s invoked by every page in your site). Next, you need to set your public Stripe key:

<script type="text/javascript">// <![CDATA[
Stripe.setPublishableKey('lksdajSDFmn2345nv');
// ]]></script>

This can take place anywhere after you’ve included the Stripe.js library (which defines the Stripe object). The value here should be your public key, found in your Stripe account settings. Do not put your private key here as: 1) that won’t work, and 2) this value will be viewable in your source code.

As a tip, if you’re already using PHP for the page, I’d recommend storing your keys as constants in a configuration file:

define('STRIPE_PRIVATE_KEY', 'l2k35j5LKJfd20m5n_l2kj34K');
define('STRIPE_PUBLIC_KEY', 'lksdajSDFmn2345nv');

Then you can have PHP print this value within the JavaScript:

echo '<script type="text/javascript">// <![CDATA[
Stripe.setPublishableKey("' . STRIPE_PUBLIC_KEY . '");
// ]]></script>';

By having PHP print this value, you can quickly change from testing to live mode by only editing your configuration file.

Next, I’d toss the rest of the JavaScript code—that which will hijack the form’s submission, make and handle the Ajax request, update the form, and submit the form—in an external JavaScript file:

<script type="text/javascript" src="js/buy.js"></script>

This script is going to do the bulk of the work, and the rest of the code explained will go in it.

Handling the Form’s Submission

The first thing the JavaScript has to do is setup an event handler for the form submission. The event handler should:

  • Disable the submit button to prevent a duplicate submission
  • Prevent the form’s submission
  • Validate the form data
  • Send the form data to Stripe via Ajax

You can do all this using straight JavaScript, of course, but I’ll use jQuery for my example. It’s easier, shorter, and more reliable. This does assume that the jQuery library will have been imported prior to this script.

Using jQuery, this code creates the event handler for the form’s submission:

$(document).ready(function() {

    // Watch for a form submission:
    $("#payment-form").submit(function(event) {

    }); // form submission

}); // document ready.

This is standard jQuery stuff and only assumes that the form has a unique ID value of payment-form. Within the innermost function, you should disable the submit button and return false to prevent the form’s actual submission:

$(document).ready(function() {
    // Watch for a form submission:
    $("#payment-form").submit(function(event) {
        $('#submitBtn').attr('disabled', 'disabled');
        return false;
    }); // form submission
}); // document ready.

This takes care of the first two obligations (assuming that your submit button has an ID value of submitBtn).

Validating the Form Data

You can use any amount of standard JavaScript to perform minimal validation on the form data. However, it’s really best to be as thorough as you can in the validation, as there’s no need to send an incomplete request to Stripe, only to wait for that response to return an error. The Stripe object, defined in Stripe.js, has several validation methods built in:

  • validateCardNumber()
  • validateCVC()
  • validateExpiry()

The first will confirm that the provided number matches the right syntax for credit cards. The second does the same for the Card Verification Code (CVC). The third method confirms that the expiration month and year are both valid and in the future.

Here’s how you might use those:

var error = false;

// Get the values:
var ccNum = $('.card-number').val(),
    cvcNum = $('.card-cvc').val(),
    expMonth = $('.card-expiry-month').val(),
    expYear = $('.card-expiry-year').val();

// Validate the number:
if (!Stripe.validateCardNumber(ccNum)) {
    error = true;
    reportError('The credit card number appears to be invalid.');
}

// Validate the CVC:
if (!Stripe.validateCVC(cvcNum)) {
    error = true;
    reportError('The CVC number appears to be invalid.');
}

// Validate the expiration:
if (!Stripe.validateExpiry(expMonth, expYear)) {
    error = true;
    reportError('The expiration date appears to be invalid.');
}

If any validation test failed, then the error variable is set to true and the Ajax request will not be performed (shown next). The reportError() function used in the above code will be explained later in this post. You may also want to validate any other form fields, but those aren’t pertinent to Stripe.

Performing the Ajax

Finally, if no errors occurred, then the Ajax request can be made:

if (!error) {
    // Get the Stripe token:
    Stripe.createToken({
        number: ccNum,
        cvc: cvcNum,
        exp_month: expMonth,
        exp_year: expYear
    }, stripeResponseHandler);
 }

As you can see in that code, the request is made through the createToken() method of the Stripe object. It takes a generic object as its first parameter. That object should pass along the payment details. Note that you must match the names of the object attributes—number, cvc, exp_month, exp_year—exactly. You can pass along other values, such as the customer’s address, using other attributes enumerated in the Stripe documentation for Stripe.js.

The second argument to createToken() is the function that should handle the method result (aka the Ajax request response). I’m calling that stripeResponseHandler, to be written next.

Handling the Ajax

The stripeResponseHandler() function is called when Stripe responds to the Ajax request. The function should take two arguments: the status of the response and the response itself.

function stripeResponseHandler(status, response) {
}

The status argument will receive the status code, which loosely emulate standard HTTP status codes. Basically, 200 is good; 400, 401, 402, and 404 generally mean you screwed up; and codes in the 500′s means Stripe’s servers messed up. If you want to be thorough, you should check and address the status code, but I’m going to omit that step in this code and focus on the response value instead.

The response is going to be an object with several properties:

  • id, which is the token identifier
  • card, information about the card (but not the card number itself)
  • currency, indicating the payment currency, such as usd
  • livemode, which will be true or false
  • used, a Boolean indicating whether this token has already been used

If an error occurred, there will be an error property, with its own message property. You should check for this first (within the stripeResponseHandler() function):

if (response.error) {
    reportError(response.error.message);
} else { // No errors, submit the form.
}

So, in short: if an error exists, report the error. Otherwise, we’re good to go! (Again, I’ll explain the reportError() function shortly.)

Within the else clause, the JavaScript needs to store the token in the form and submit the form:

// Get a reference to the form:
var f = $("#payment-form");

// Get the token from the response:
var token = response.id;

// Add the token to the form:
f.append('<input type="hidden" name="stripeToken" value="' + token + '" />');

// Submit the form:
f.get(0).submit();

And that’s that! If everything went smoothly, the token gets stored in a hidden form input and the form is submitted to the server, but the payment information is not provided to the server, because those form elements have no name attributes. The server will be able to use $_POST['stripeToken'] to actually process the payment, as will be explained in the next post.

Displaying Errors

Because errors could occur in several places, I think it best to create a JavaScript function that handles any error, which I’ll call reportError(). This function takes the error message as an argument and should:

  • Add that message to the page
  • Set the error class on the message
  • Enable the submit button

This last step is necessary because the form handling function disables the submit button. If you don’t re-enable it, then the customer can never resubmit the form after correcting the error.

For the first two steps, a single line of jQuery will do. Here’s the complete function:

function reportError(msg) {

    // Show the error in the form:
    $('#payment-errors').text(msg).addClass('error');

    // Re-enable the submit button:
    $('#submitBtn').prop('disabled', false);

    return false;

}

This does assume that you’ve already created an element with an ID of payment-errors, that the submit button has an ID of submitBtn, and that you’ve defined a CSS class named error. This function is also written to only display a single error at a time. You could change it to concatenate each error to the #payment-errors content, in which case you’d need to write a clearErrors() function that gets called with each form submission (so that previous errors are not retained).

Conclusion

And there you have the JavaScript for handling the form and performing the Stripe request. It’s about 100 lines total, when well-spaced and documented (and, again, I’ll make all the code available via download later on).

In the next post, probably in two weeks, I’ll walk you through the PHP code that will handle the form data. In the meantime, if you have any questions or comments, please let me know.

If you enjoyed this post, then please consider following me using your favorite social media, the RSS feed, and/or by subscribing to my newsletter. Or go crazy, and buy one or more of my books . Thanks!

20 responses to Writing the JavaScript Code for Handling Stripe Payments

  1. When you get a stripe token back via the stripeResponseHandler, you then submit the form to the server. But, the form’s submit event has already been trapped earlier. You end up in an endless loop of resubmitting the form again and again ($(“#payment-form”).submit(function(event)).

    How do you get around this?

    • Thanks for the question. I screwed up the original code. My apologies. I’ve changed it to be correct.

      • Larry, I set up the code and tried it out and ran in to exactly the same problem that Jon described. This may not have been true when you wrote this article, but it certainly happens when I tested using jQuery 1.9.1. Perhaps something has changed.

        I got around this infinite loop by adding this to the javascript inside of the submit handler:

        if(typeof $(‘[name="stripeToken"]‘).val() !== ‘undefined’){
        return true;
        }

        This will checks to make sure that the stripeToken is present, then simply returns true and submits the form normally.

        Hopefully that helps you out, Jon.

        • Nope, I totally screwed up. My apologies to Jon and to anyone else caught by this. The solution is a bit esoteric: in the Ajax handler, submit the form using f.get(0).submit();. I’ve changed the code above and the downloads. Thanks, Adam, for the help, too.

          • Thanks guys. I’m curious, what does f.get(0).submit() do that f.submit() wouldn’t, other than grabbing a reference to the first element of the form(here as variable f)?

          • The main thing is that f.get(0).submit() doesn’t trigger a form submission event on the form that f.submit() would. If there’s another form submission event, you end up in an endless loop (I made this mistake in my original posted code).

  2. If we want to add and validate some additional form inputs for handling the credit card payment such as name, address and zip, does anyone have thoughts on the risks or disadvantages of doing this validation using jquery rather than waiting for the form to successfully post thereby allowing you to validate with PHP?

    • It’s not an either/or: You absolutely must do validation in PHP. Always. The client-side validation is a benefit to the user: provides immediate feedback without needing to submit the data to the server and await a server response.

  3. I’m walking through this tutorial (I’m very appreciative for your thoroughness!) and I noticed that the form input values are being targeted with a class selector, i.e. expYear = $(‘.card-expiry-year’).val(); I’m curious, how does this select the value when the html has no classes defined?

    Thanks.

  4. i have generate token already, and want to make payment later , how i ignore Stripe.createToken() and get the token from my own database for payment?

  5. Hi, I have follow the same process as mention. get success with validation and stripeToken gets. but when form get submitted then stripeToken is not append to form and also check with the account no success transaction is displayed. plz help me out.

    thanks in advanced waiting for your reply

  6. Hi, I am using the stripe form you created and I have everything working but for some reason it keeps saying javascript is not enabled on my browsers and I have enabled it on all of them and I cannot submit the form to test it because of javascript Please help. Thanks

  7. And how do you process a card_declined using ajax? I’ve used a card value of 4000000000000002 to trigger card_declined but it always returns status 200 and no error to the stripeResponseHandler!!

  8. Hi larry, I tried to create a payment button with stripe and php, but I can not do it. if you like it you can show me the steps to create this button. thank you

  9. How is it that all the code examples on the Stripe web site are a complete and utter mess. They are filled with bugs that have to be fixed etc. How are people without much experience suppose to learn anything if you so called experts cannot even get it right! Thanks for the hours of wasted time; like getting the javascript is not enabled error even after I checked to see that Chrome was indeed running javascript! Bunch of Hacks.

Trackbacks and Pingbacks:

  1. Writing the PHP Code to Process Payments with Stripe | Larry Ullman - February 18, 2013

    [...] Writing the JavaScript Code for Handling Stripe Payments [...]

Comments are great, but I'd strongly prefer any requests for assistance get made in the support forums. Thanks!