1. Code
  2. PHP

How to Accept Payments With Stripe

Scroll to top
Read Time: 15 min

Processing credit cards is unfortunately far more difficult than we might hope, as developers. Given that it’s such a common task, is it really necessary that we jump through countless hoops (surrounded by fire, of course) for the sole purpose of processing a payment? Merchants? Gateways? SSL? Security? Very quickly, a seemingly simple operation can become an overwhelmingly confusing and, more importantly, dangerous task. Any time that you find yourself handling a user’s sensitive data, you better be on your toes.

Stripe translates a complicated, confusing, and dangerous operation into a simple API call.

Wouldn’t be it amazing if there was a service that made this process as easy as it can possibly be? A service built by developers for developers. What a thought! Enter Stripe; no merchant accounts, no gateways. An API call, along with a few safety guidelines, is all that you need to begin accepting credit card payments today.

While Stripe isn’t free, they only ask for 2.9% of each charge (plus .30 cents). That’s it. No setup fees, storage fees, hidden costs - none of that. Just 2.9%. Not bad!

5 Key Stripe Features

  1. Simple: Processing credit cards manually is difficult and dangerous. With Stripe, doing so is a cinch! You can even process charges from the command line!
  2. Cheap: Various payment merchants are notorious for their hidden fees. Stripe tells you up front exactly what you can expect to pay: 2.9% per charge + 30 cents. No setup fees. No hidden fees. No card storage fees.
  3. Intuitive API: Stripe’s API is clean, restful, and easy to use.
  4. Used By Cool Kids: If adoption is a concern, it needn’t be. Countless services leverage Stripe, including Reddit, Grooveshark, and Shopify.
  5. Built By Developers: Very clearly, Stripe was built to scratch a developer’s itch. The team is full of developers and entrepreneurs, just like you.

Let’s Do This

Sold? I was too. Let’s process our first test payment. Of course, before beginning, visit, create a new account (free), and fill out the various forms, such as the statement descriptor and your banking information.

Stripe's attention to elegance extends to its design department.

Charging a user requires two core steps:

  1. Fetch the user’s credit card information, and send an AJAX request to Stripe’s server, which will return a unique token that represents this secure data.
  2. Using your server-side language of choice (PHP for this article), create a new Stripe charge, passing through the unique token.

Build a Payment Form

Naturally, the first step is to build a payment form for your product. You have two options: use Stripe’s checkout script, which will automatically create the form, validate the user’s input, and generate the unique token for the user’s credit card data. In situations when configuration and styling are flexible, this is an excellent route to take. Insert a script tag, along with a handful of custom HTML5 attributes, and you’re done!

Stripe offers an embeddable form that further expedites the process of accepting payments.

However, in most situations, you’ll require full control. As such, for the purposes of this article, we’ll use a custom form. In this section, we’ll accomplish three things:

  1. Use a form to collect the user’s credit card information
  2. Convert that data to a unique single-use token
  3. Submit the form to the server, along with the token

A basic payment form might look like:

Notice how we don’t require much information to process a credit card. Technically, the only information that Stripe demands is a credit card number and expiration date. However, as a rule of thumb, the more information that you fetch from the user, the better. Should the charge be disputed, this extra information will come in handy. Or, in other words, the more information you request, the more likely it is that the true owner of the credit card is placing the transaction. The key is to find the line between enough and so much that the user doesn’t bother filling out the form. At minimum, request the user’s name, email address, credit card number, expiration date, and CVC number.

To continue drilling into your head, never allow sensitive credit card data to touch your server. Doing so has the potential to create a world of hurt, if performed incorrectly. Instead, take the easy road: ensure that the inputs for the user’s credit card data do not contain name attributes. By omitting this attribute, the data can’t be posted to your server.

Pay close attention to the custom attributes on the inputs, such as data-stripe="number". Stripe offers a plugin, stripe.js, which assists in the process of compiling the user’s provided data, and generating the token. Stripe will search for those attributes and fetch their respective values.

To make use of stripe.js, reference the script within your project, and set your publishable key, which will be provided when you sign up with Stripe. We’ll also be using jQuery in this article, though it’s certainly not required.

Think of setPublishableKey as a way of identifying your website when communicating with Stripe. Upon signing up, you’ll be presented with two different versions of this key, for testing and production, respectively.

Next, we need to create the unique, single-use token for the user’s credit card data. We can use the Stripe object, provided by the script that we imported, for this purpose. Even better, we needn’t worry about serializing the payment form’s data; simply pass through the form jQuery object, and Stripe will handle the rest.

With this bit of JavaScript, when the payment form is submitted, Stripe will attempt to generate a single-use token, using the related data from the inputs that include stripe- specific custom attributes. The second argument to the create method is a callback that will receive the token ( from Stripe’s server, and proceed accordingly.

Within this callback, it’s important to verify the result (was all of the information provided correctly), insert the token into a hidden input, and submit the form to your server. Again, note that the credit card information should/will not hit your server - only the token and non-sensitive data. This is important, so write acceptance or functional tests to verify it.

Your callback might look like so:

It’s really quite simple! Submit an AJAX request to Stripe’s API (using their helpful JavaScript plugin), fetch the generated token, insert it into the form, and post it to your server!


If following along, at this point, you’ve successfully generated a single-use token and submitted the payment form. Now, it’s time for your server-side language of choice to physically create the charge. Remember, in the previous section, no charge was made. We only generated a token that represented the credit card data.

Stripe offers a number of server-side libraries for registering new charges, or even arranging subscriptions. Chances are high that your preferred language is represented (PHP, Ruby, Python, etc.).

Similar to the previous section, submitting a new charge may be accomplished in a few steps:

  1. Declare your API key
  2. Using the Stripe library, make an API call, passing through the details of the transaction
  3. Validate the charge, and proceed accordingly.

Refer to Stripe’s Library page for installation instructions. If using PHP, as we will be in this article, it’s recommended that you leverage Composer to download the Stripe package.

Composer is the future of PHP dependency management, so get on board now, if you haven’t already. A basic Stripe charge might take the form of:

That’s it! The API key will authenticate you as a valid Stripe user. Similar to the publishable key, Stripe will provide you with two different versions of this key: one for testing and production, respectively.

Please note that all charges to Stripe should be declared in cents (based on the currency, of course). If prices are stored in your database as dollars, euros, or pounds, then you’ll want to compensate accordingly, when making the charge.

If no exception is thrown, you may rest assured that the charge has successfully processed. Proceed by offering the user their digital download, or registering their purchase with your system.

Believe it or not, Stripe’s work is finished. There’s certainly more that you can do, such as creating customers and managing subscriptions, but, when it comes to simply processing a single payment, you’re done! …Except you’re not.


While, yes, Stripe’s work is finished, yours, on the other hand, is not. Regardless of the payment provider, any time that you work with credit card information, security should be a top concern. We’ve already taken the first steps, by ensuring that the credit card data never touches the server, but there’s still more to do. We next must secure the user’s connection to your server. In other words, you need an SSL certificate. Under no circumstances should you skip this step!

“SSL (Secure Sockets Layer) is the standard security technology for establishing an encrypted link between a web server and a browser. This link ensures that all data passed between the web server and browsers remain private and integral.” -

When a user offers a website their credit card information, they will expect to see https within the address bar. Luckily, purchasing an SSL certificate is far easier than it used to be. In fact, most hosts offer an SSL add-on, which turns the entire process into a single click. The same is true for various SaaS options, such as Pagoda Box or Heroku.

Tip: Once you enable SSL, it’s possible that images and assets will break. To fix this, ensure that all URLs use https, rather than http. Or, as a better solution, use protocol-relative URLs.

With this techique, popularized by Paul Irish, if the current page is using HTTPS, then the asset will also be requested with HTTPS.

Assuming that your host offers a one-click SSL add-on, simply point your user to the https:// version of the order page, and you’re all set to go!

Tips and Tricks

The examples in this article are simple and mostly procedural. Chances are high, though, that you’ll be working with a framework that supports multiple environments, routing, and testing facilities. Use the following tips as a head-start for integrating Stripe with your framework of choice.

1. Special Credit Card Numbers

Clearly, you don’t want to use real credit card numbers to test your payment forms! Luckily, Stripe has already thought of this; they include a number of credit card numbers that simulate specific responses, such as a successful charge, invalid number, incorrect CVC code, and many more.

Here are a few card numbers that you’ll frequently reference:

  • Visa Approved: 4242424242424242
  • Mastercard Approved: 5555555555554444
  • Card Declined: 4000000000000002
  • Incorrect Number: 4242424242424241

2. Use Environments Wisely

When working with Stripe, you’ll have two unique keys, which represent the API and publishable keys. Further, there are testing and production variants for each of these. Most frameworks offer a way to manage multiple environments. This way, for development, your application will correctly use the testing keys, while, once deployed, the production versions will be referenced.

Below is a Laravel-specific project. Laravel provides a simple environment system. Add a configuration file within a folder that corresponds to the environment name, and those values will take precendence over the defaults.

First, we set the production keys:

And for development, we override the production keys with their test counterparts:

Now, when the application requires the API key, using Config::get('stripe.apiKey'), the value that is returned will be determined by the environment. Success!

3. Don’t Hardwire Your App to Stripe

A common mistake that beginning developers make stems from linking their applications to various providers, like Stripe. Your application shouldn’t care which billing provider is being used. It’s only concerned with the fact that one is available. By hard-coding references to Stripe in your classes, you are creating a direct connection between the two - one that will likely be difficult to change.

Ask yourself, “If, in the future, I need to swap out Stripe with a different provider, how difficult will that be?” Hint: anything greater than “just a moment” is a code smell.

Instead, code to an interface - perhaps BillingProvider or BillingGateway. This way, you may create various implementations of the interface: one for Stripe, or one for a different service entirely, should the need arise. These various implementations will house the service-specific functionality. If, at some point, you find a cheaper billing provider than Stripe, swapping out the Stripe implementation of BillingProvider with a ServiceX version will only take a moment - that is, once you’ve created the new implementation that queries the ServiceX billing API.

Here’s a skeleton for how this might look:

Now that we have two implementations, we may reference our current preferred billing service, using dependency injection.

With this style of development, if you do end up needing to move away from Stripe, the controller won’t need to be touched. Because Stripe isn’t hard-coded, it doesn’t know the difference!

4. Don’t Leave the Buyer Hanging

When selling digital goods, ask yourself, “What should the buyer do if something goes wrong on my end?” Always provide some way for the buyer to contact you or your company. What if the confirmation email that includes a link to download the digital file never arrives in the buyer’s inbox? What should they do?

A support site, or even a simple email address on the home page should help in these inevitable situations.

5. SSL Certificates

DigiCert is Stripes recommended SSL certificate provider.

If you must manually purchase an SSL certificate, there are a number of services to choose from. Based upon prior experience, you can expect to spend thirty minutes to an hour setting things up. Keep in mind that most certificates are not free, and can range from $10-$500, dependent upon the provider.

The Stripe team recommends DigiCert and Namecheap, though, if you prefer, you might consider a free solution, such as StartSSL.

6. Don’t Rely on the Form’s Price

A frequent mistake stems from using form data to contain the price of the product being purchased, possibly via a hidden input. Because a user can easily edit this input’s value, it’s unwise to depend on it. Always fetch the price of the product from the server-side. Never rely on the form to tell you. A simple database query is the preferred option.

7. The Digital File Should Not Be Publicly Accessible

The asset that you are selling should never be accessible by the public, even if the URL is, in your opinion, long and confusing enough to the point that most would never learn it. This is a bad practice for a number of reasons.

Instead, create a downloads table which houses unique purchase codes, along with their associate product ids. This way, when a URI, such as /downloads/23gsfga831g, is requested, your application will:

  1. Verify the provided token against what is stored in the database table.
  2. Respond by offering a download for the file that is associated with the purchase token.

To take things further, you might also enforce a download limit. Allowing for this would simply require that a download_count field be added to the purchases table. With each request, that number should be incremented by one. Once this number reaches your designated threshold, the download should no longer be provided. This can be helpful in instances when you want to ensure that download links aren’t shared.


The wonderful thing about Stripe is that it translates a complicated, confusing, and dangerous operation into a single, simple API call. No merchant accounts, no gateways, no hidden fees. There’s a reason why they say that Stripe is laughably easy to use. It is!

Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.