Creating a Form for Handling Payments with Stripe

November 28, 2012 — 19 Comments
This entry is part 4 of 8 in the series Processing Payments with Stripe

Once you’ve created a Stripe account and have acquired an SSL certificate, you’re ready to write the form through which you’ll accept payments to be processed via Stripe. This is surprisingly simple to do, and completely secure when done right. In this post, I’ll explain what you need to do with your HTML.

Two Traditional Payment Approaches

Before discussing the form, you should be clear as to how Stripe works compared to traditional payment processing approaches. Historically, depending upon the payment system in use, there were two possible processes:

  • The user is sent from your site to the payment processor’s site, where the payment information will be taken. The user is then hopefully returned to your site.
  • Your site takes the payment information and passes it to the payment processor behind the scenes. The user never leaves your site.

In both scenarios, the user’s payment information needs to get to the payment processor, and the payment processer needs to convey the success of that payment back to your site. What people normally think of as PayPal takes the first approach. Other payment gateways, such as Authorize.net, traditionally use the second approach.

Many payment processors, including PayPal and Authorize.net, now support both onsite or offsite payment processing (not at the same time, but you can choose which approach you want to use).

In the first scenario, the user is aware that she is leaving your site, you’re limited in how much you can customize that experience, and you have to put in a fair amount of work on your site to verify that the payment was made. On the other hand, because your site is not handling any of the payment information, you have a limited amount of risk.

With the second scenario, the user never leaves your site, you can completely customize the experience, and it’s easier to confirm that a successful payment was made. However, your security risk and exposure goes from being rather minimal to extremely serious.

If a user’s credit card or other payment information reaches your server, you must be PCI compliant and take many more steps to protect both the user and your business. In short, not only should you never store the user’s payment information, you really ought not to have it in your possession either, even momentarily.

Stripe’s Approach

Stripe has developed a great middle ground between these two approaches. Thanks to the Stripe.js JavaScript library, you can have your proverbial cake and eat it, too. Using Stripe.js, the user never leaves your website AND you aren’t exposed to extra security risks because the user’s payment information will not touch your server. The process works like so:

  1. You create a form on your website that accepts the payment details.
  2. You include a Stripe JavaScript library on the page.
  3. You write a JavaScript function that watches for the form submission (i.e., you create an event handler for the form’s submission).
  4. When the form is submitted, the user’s payment details are securely sent to Stripe via Ajax.
  5. Stripe will confirm that the payment information is valid and return a token that uniquely identifies that payment information.
  6. The JavaScript function that handles the Ajax response stores the token in a hidden form element and submits the form.
  7. The server-side script (aka, the PHP code) that handles the form’s submission uses the token to actually process the payment.

So the customer never leaves your site but the payment information never hits your server: the best of both worlds. (This is the process when all works well; payment verification errors introduce new processes.)

In this post, I’ll explain how to set this all up in your HTML. In the next post, I’ll walk you through the necessary JavaScript functions. And in the following post, I’ll start creating the PHP code that performs the payment request.

The HTML Page and Form

To start, you need to include the Stripe.js library on your payment page:

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

As you can see, this library is hosted on Stripe’s server. You don’t have to download and install it on your site. Note that this library is loaded over HTTPS, and your HTML page (i.e., the one with the payment form on it) must be loaded via HTTPS, too.

When using Stripe.js, your only requirement to be PCI compliant is that the HTML form is loaded via HTTPS.

For the form itself, let’s assume that the name of the HTML page is buy.php, and it will both display and handle the form:

<form id="payment-form" action="buy.php" method="POST">
<div id="payment-errors"></div>
</form>

The form should use the POST method, and you’ll also want to give the form a unique ID value, for later use in the JavaScript code.

Within the form, you might as well go ahead and create a spot for showing errors. This also needs a unique ID value, and will also be used by the JavaScript.

For the form elements, it’s really up to you what all the form has. At the very least, you’ll need to have fields for the:

  • Credit card number
  • Expiration month
  • Expiration year

Logically, you may also want to take the Card Verification Code (CVC) number.

Stripe does not have a set validation requirement; Stripe will only validate the information it receives. If you pass Stripe the CVC number, too, Stripe will validate that along with the credit card information. The user’s name and billing address is entirely optional from a payment validation perspective. The street address is not reliable for validation purposes, although the zip code can be checked (for US addresses).

You don’t have to ask for the credit card type, either, as that’s knowable information from just the credit card number.

Stripe Payments Form

It does not matter what input types you use for these elements; text is fine, although you can use the HTML5 number type for the month and year, if you’d rather. In any case, the most important factor is this: do not provide name values for these form elements! You should also set the autocomplete property to off for each element, so that the user’s browser does not attempt to save the values:

<label>Card Number</label>
<input type="text" size="20" autocomplete="off">
<span>Enter the number without spaces or hyphens.</span>
<label>CVC</label>
<input type="text" size="4" autocomplete="off">
<label>Expiration (MM/YYYY)</label>
<input type="text" size="2">
<span> / </span>
<input type="text" size="4">

AGAIN: DO NOT PROVIDE NAME VALUES FOR YOUR PAYMENT FORM ELEMENTS!

You may be wondering what this name thing is all about. Well, Stripe takes advantage of a little-known quality of HTML forms. If you do PHP programming, you know that the names of your form elements correspond to the names of the indexes wherein you can access the form data: $_POST['name'], $_POST['email'], etc. Taking this knowledge a step further, it turns out that if you don’t provide a name for a form element, then that element’s value will not be accessible to the server. This is how you protect the user and your business: the user’s payment information never actually gets to your server! Your server will, however, receive the Stripe-provided token, which represents the payment option (it will be stored in a hidden form element via JavaScript and DOM manipulation).

If you want, you can add anything else you need to the form, such as the user’s email address or a password input (to create an account) or whatever. Those other fields will be standard HTML forms, with name attributes, whose values get sent to your server but not to Stripe.

Alternative Stripe Approaches

In the next article, I’ll walk you through the JavaScript used to handle the form’s submission, perform an Ajax request of the Stripe service, and handle that request result. To wrap up this post, though, I want to mention two other ways you can use Stripe. I believe that using Stripe.js is the safest and easiest route, but it does require that JavaScript be enabled. Normally I try to avoid requiring JavaScript on a website, but as this is a matter of user security and convenience, I think it’s a reasonable requirement.

That being said, if you’d rather not rely upon Stripe.js for whatever reason, you can use PHP or your favorite other language to communicate with Stripe behind the scenes (as in the second outlined scenario). Note that doing so greatly increases your security vulnerability and exposure as you will have to handle the user’s payment information on your server. But if that’s something you’re up to doing, and you’re capable of maintaining PCI compliance, it is an option.

Second, if you want something simpler than what I’m outlining and don’t mind relying upon JavaScript, then you’re also in luck. Despite the fact that Stripe is crazy easy to use, Stripe has another route that is even easier. It’s called Checkout, and it simplifies the process of creating the HTML form and JavaScript required by the payment process. You’ll still need the server-side code that processes the actual charge, however.

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!

19 responses to Creating a Form for Handling Payments with Stripe

  1. Awesome article. Might implement such a solution in the new year. Been hesitant to handle payments security wise, so this seems like a nice solution.

  2. I want to use drop down for expiry_month and expiry_year fields. How can i handle?

    • Just create drop-downs and use the same names for the drop-downs as the code uses for the text inputs. Use two-digit numerals for the values.

  3. Great articles, found them very illuminating in building a CakePHP plugin.
    Just an observation, version 2 is now available for Stripe.js:
    https://js.stripe.com/v2/

  4. Hi Larry,

    Very helpful article on Stripe, thank you. I have created my Stripe account (test and live), installed the SSL, reviewed some tutorials, etc, but cannot seem to find any way to add a simple “Amount” field for the customer to enter the amount they wish to pay.

    Is there a way, with a Stripe form, to add an “Amount” field? For example, a customer enters the amount 642.35, enters their credit card info, and receives an email for the transaction?

    Hope this makes sense. I have saved your site as a Fav.

    Thanks so much for any input or other references.

    • Thanks for your feedback. In answer to your question, you’d just create the “amount” field yourself. It’s when you actually charge the user (e.g., using PHP), that you’d pass the amount along to Stripe. You can then also send the customer the email or you can have Stripe do it for you.

  5. So Strips has 3 different, separate, credit card payment interfaces. I totally missed that from their web site. Thank you for your article above.

  6. Larry great series.

    I have used a plug in (press pay) to link up with my Word press site.I cant see any mention of a plug in above. Do I still have to go through the coding practices above, or is it all done for me with the plug in?

  7. Dhaval J Parekh April 9, 2014 at 9:29 am

    PS: Sorry for posting same comment again as I missed to check the option for notify via email :)

    First of all thanks for such a nice demo.

    I noticed that Stripe is getting local date / time for validating the expiry date which seems not valid. I tested with changing the date / time of my system to Feb 2013 and its allowing me the card which expires on May 2013.

    So, my question is that is there any method or demo where I can put server side validation for that or in this case what to do for the accurate expire date validation?

    • Thanks for the question. Stripe.js does heuristic validation: does it look okay? That would mean using local date/time for client-side validation. But when you try to run a charge through the card, Stripe will take the information to the bank, at which point the bad expiration date would be caught.

  8. H mate,

    I have used your downloaded code and changed key.. but getting this error after entering correct credit card details..
    “The expiration date appears to be invalid.”

  9. Hey, great article.

    I want to use stripe with my website and once i press the buy button of the product I would like to be able to fill a form with additions to the purchase. These additions increase the price, almost like a cart but more like a form. Do you think it possible for the form to collect the correct price and then send it through the stripe process?

  10. Downloaded the code but when I try to run buy.php I get the following error

    Internal Server Error
    The server encountered an internal error or misconfiguration and was unable to complete your request.

    Please contact the server administrator to inform of the time the error occurred and of anything you might have done that may have caused the error.

    More information about this error may be available in the server error log.

Trackbacks and Pingbacks:

  1. Writing the JavaScript Code for Handling Stripe Payments | Larry Ullman - December 5, 2012

    [...] to StripeCreating a Stripe Payments Test AccountGetting an SSL Certificate/Setting Up HTTPSCreating a Form for Handling Payments with StripeWriting the JavaScript Code for Handling Stripe PaymentsIn my previous post in this series, I [...]

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

    [...] Creating a Form for Handling Payments with Stripe [...]

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