Logo de Stripe - Infrastructure de paiement pour le commerce en ligne
Expertise

Making a simple payment with Stripe

Publié le : 5 octobre 2018
Temps de lecture : 4 minutes

Stripe is a powerful payment service designed for developers, but it can be difficult to use for newcomers even if the documentation is really good. Let’s make an example for a simple payment with a credit card on a Symfony app.

Prerequisites

Be sure to create an account and configure it, you won’t be able to test anything without a Stripe account as you will need your api keys for that.

There are several ways to work with Stripe and achieve a single payment with a credit card, in this article we will tokenize the card details and then charge this card.

Front

Set up the Stripe.js script

First things first, you need to import the Stripe.js library and instantiate the stripe object, which can easily be done with the following code:

<script type= »text/javascript » src= »https://js.stripe.com/v3/« ></script>
<script>
const stripe = Stripe(‘pk_test_UseYourPublishableKeyHere’);
</script>

Stripe recommends you not only to import the script on the payment pages of your site, but on every page, as it packages an advanced fraud functionality.

Create our payment form

Now that we have prepared the script, we need a form to let the user put his card details. We will use the Elements to create our form, so we can use the following:

<form action="/charge" method="post" id="payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element">
<!-- a Stripe Element will be inserted here. -->
</div><!-- Used to display Element errors -->
<div id="card-errors" role="alert"></div>
</div><button>Submit Payment</button>
</form>

For now if you try to display the page, all you have is an empty form without any input. We need to instantiate the Element in our script to fill the form with a Stripe form for the card:

const elements = stripe.elements();
const card = elements.create(‘card’);
card.mount(‘#card-element’);

We will now retrieve a set of inputs allowing the user to fill its card details. Those inputs come with a nice UX and error management so you can concentrate on more important things.

Create the token

Everything is ready, so now let’s get on with the source creation. The first thing to do with our form is to create a token with the payment details. The token creation ensures that you do not pass any sensitive data to your server. Thanks to the card Element, this is easy, all we need to do is to call the method stripe.createToken(card). Add some error management and use the promise sent back to obtain the following:

const form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault(); stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error
const errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server
stripeTokenHandler(result.token);
}
});
});

Now that we have our token, we need to send it to our server, and we can do it thanks to a hidden input:

function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
const form = document.getElementById('payment-form');
const hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput); // Submit the form
form.submit();
}

Please note that the Element’s fields are not sent to the server with this code, meaning that you are operating in a PCI compliant way. This way, we can send all the data we had in our form with the token and your server never receives sensitive card details from your request (card number, expiracy date, cvc).

Backend

For the backend we will be using Symfony and Composer to install dependencies. In order to have something reusable later, we will create a service for all our Stripe methods.

Install

To use Stripe in our backend Application, we need to install the stripe-php library. All you need to do is to run the following command:

composer require stripe/stripe-php

Stripe Service

For starters, we need to save our API keys. Let’s add our key in the app/config/parameters.yml file, like so:

stripe_secret_key: sk_test_UseYourSecretKeyHere stripe_publishable_key: pk_test_UseYourPublishableKeyHere

This way, we can specify for each instance the keys to use, test keys for the test instance and the live keys for our production environment.

Now we can create our service. This service will need the secret key to initialize the Stripe library, so it will look like this:

<?php
namespace AppBundle\Services;use Stripe\Stripe;class StripeService
{
public function __construct(string $stripeSecretKey)
{
Stripe::setApiKey($stripeSecretKey);
}
}

And now we can register our service in the app/config/services.yml config file:

AppBundle\Services\StripeService:
arguments: [‘%stripe_secret_key%’]
public: true

Now that we have a functional service for the Stripe library, let’s make our first payment.

Payment Request

Now let’s implement the charge mechanism in our Stripe service:

/**
* @throws \Stripe\Error\Card
*/
public function charge(string $token)
{
$charge = \Stripe\Charge::create([
'amount' => 4200, // Amount in cents
'currency' => 'eur',
'description' => 'Example charge',
'source' => $token,
]); return $charge;
}

With this simple code, we can process a payment of 42.00€ (passed in cents to the API), with the card corresponding to the token given. The description is a text that will appear in your Stripe dashboard and on the client bank receipt. Now all we have to do is use this method in our controller :

/**
* @Route("/charge", name="charge_simple")
* @Method({"POST"})
*/
public function chargeAction(Request $request)
{
if (!$request->request->has('stripeToken')) {
return new BadRequestHttpException('No stripe token to create charge');
} $charge = $this->container
->get(StripeService::class)
->charge($request->request->get('stripeToken')); $amount = $charge->amount / 100; // Amount is in cents $this->addFlash(
'notice',
"Charge of $amount € successful !"
); return $this->redirectToRoute('homepage');
}

This action is pretty straightforward, we retrieve the token, charge the card, and display a message. Clean and simple.

But what if there is a problem and the card cannot be charged? The charge method of the Stripe library throws an exception that will help you manage those errors, so you can do something like this:

try {
$charge = $this->get(StripeService::class)->charge($params['stripeToken']); $amount = $charge->amount / 100; // Amount is in cents
$this->addFlash(
'notice',
"Charge of $amount € successful !"
);
} catch (\Stripe\Error\Card $e) {
$this->addFlash(
'error',
$e->getMessage()
);
}

The message of the exception is readable by your customers (if they are english speakers). If you want to provide internationalization, you can rely on the Stripe error code, that you can get with $e->getStripeCode().

So that’s pretty much all you need to know to process payments with Stripe. The front part is almost done by Stripe itself and the back is easy to use, and everything is secure, so it’s worth a try. If you need an example of this test case, we got a github repository to help you test that!

If you have other questions related to Stripe, don’t hesitate to comment down below, and we’ll try our best to answer quickly and if you are interested in other articles about Stripe be sure to tell us!

Florent Lucas
Responsable Commercial & Marketing @thetribe