Building a Subscription Signup Form

Create a subscription signup form using Checkout, and use the Stripe API to complete the signup process. If you need help after reading this, check out our answers to common questions or chat live with other developers in #stripe on freenode.

Emma’s farm runs a successful Community Supported Agriculture (CSA) program, where customers sign up for a weekly delivery of delicious fruits and veggies. She’s decided to use Stripe to manage her customer’s subscriptions, starting with an online signup form. This recipe shows how Emma:

  • Creates a plan using the Stripe Dashboard
  • Builds a signup page for her website using Checkout and some PHP code
  • Tests her work using Stripe’s test mode and test credit cards

Although this example uses Checkout and PHP, you can also use Stripe.js with your own form, and any programming language you’d like.

Using test mode

Stripe accounts have both a live and a test mode. The two modes exist in parallel; you can always try something out in test mode, even after you’ve gone live with your site. Test mode differs from live mode in that you can’t use real credit cards, only test card numbers. Every Stripe interaction can be in either live or test mode simply by using live or test API keys. Emma follows the standard development route by starting in test mode, and when she is satisfied with the work, swapping her test keys for her live keys.

Creating a plan

The first thing Emma needs to do is create a plan in her Stripe account. A plan defines the terms of a customer’s subscription: how much they will be billed and how often. You can create a plan using either the Dashboard or the API, here Emma is going to use the Dashboard. To create the plan, Emma logs into her account Dashboard, toggles to test mode, and clicks Plans under the Subscriptions heading. This video shows the actual plan creation.

The plan dictates that Emma’s customers will be charged $20 every week, and the charge on their credit card statement will say “EMMAS FARM CSA”. The name of the plan is what her website will show to her customers. The ID will be used when a subscription to this plan is created using the API.

Creating the signup form using Checkout

Now that Emma has created the plan within Stripe, it’s time to create the sign up form where her customers enter their payment details. She will use Checkout, an easy and elegant solution. Here’s how Checkout works within an application:

  1. When the customer clicks the “Sign Me Up!” button on Emma’s website, Checkout shows them a form where they will enter their payment information.
  2. The payment information will be directly and securely sent to Stripe, where the payment information is converted to a representative token and sent back to their browser. Emma’s site can use this token without ever having to see her customer’s payment information. This approach makes Emma’s site more secure for her customers and reduces her PCI compliance burden.
  3. When the call to Stripe returns the token to the customer’s browser, Checkout automatically submits the subscription form, with the token, to Emma’s web server.
  4. Emma’s application takes the form information, builds a request to create a subscription, and sends that request to Stripe.
  5. Stripe creates a customer in Emma’s account with the payment information, and attempts to bills them for the first interval of the subscription. If successful, it creates a subscription for the customer and returns the information to Emma’s application.

An important note is that both Checkout and the server-side code are required. Checkout securely accepts the customer’s payment information and the server-side code creates the actual subscription in Stripe.

Emma would like to get the form up as soon as possible, so she decides to collect just the minimum amount of customer information she needs: the customer’s email address and their payment information. Checkout collects both of these for her, so she doesn’t need to do much. She creates a very simple webpage, signup.html, that includes an explanation of the CSA and a signup button that opens Checkout.

Landing page with the signup button.

Landing page with the signup button.

When the customer clicks the “Sign Me Up!” button, the Checkout window opens and the customer is prompted for their email and payment information.

Here’s the code Emma adds to the page that creates the “Sign Me Up!” button and customizes Checkout:

<form action="/create_subscription.php" method="POST">
  <script
    src="https://checkout.stripe.com/checkout.js" class="stripe-button"
    data-key="pk_test_6pRNASCoBOKtIshFeQd4XMUh"
    data-image="images/marketplace.png"
    data-name="Emma's Farm CSA"
    data-description="Subscription for 1 weekly box"
    data-amount="2000"
    data-label="Sign Me Up!">
  </script>
</form>

There are two HTML elements here: a form, and inside it, a script.

  • Line 3 imports Checkout and styles the “Sign Me Up!” button.
  • Line 4 sets the data-key attribute, which needs to be the account’s publishable API key. We’ve placed a random API key in the code. Replace this with your actual API key to test this code for yourself.
  • Line 5 sets the image that seen at the top of the Checkout window, data-image, in this case a green house or farmstand. This image is served from Emma’s website, with the other images her website uses.
  • Lines 6 and 7 set the Checkout title and description text via data-name and data-description.
  • Line 8 sets the price the customer will see in data-amount. This value is in cents, so $20 is set as 2000.
  • Line 9 controls the text on the button, data-label, in this case “Sign Me Up!”. If you don’t set a label, the default label on the button will be “Pay With Card”.

The script tag handles the Checkout configuration. The form doesn’t have any elements that are visible to the customer, but it serves a crucial function for Checkout. When Checkout receives the token from Stripe it appends two hidden fields to the form: stripeToken and stripeEmail. Checkout then submits the form to Emma’s server. Let’s look at what Emma needs to do to after the form is submitted to complete the subscription sign up.

Create a subscription for the customer

As mentioned above, Checkout appends stripeToken and stripeEmail to the signup form and submits it to the server. Emma uses those parameters to build a Stripe API call to create a subscription. She makes a PHP file named create_subscription.php (which matches the form’s action attribute value above), and adds the code to create the customer:

<?php // Create a customer using a Stripe token

// If you're using Composer, use Composer's autoload:
require_once('vendor/autoload.php');

// Be sure to replace this with your actual test API key
// (switch to the live key later)
\Stripe\Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");

try
{
  $customer = \Stripe\Customer::create(array(
    'email' => $_POST['stripeEmail'],
    'source'  => $_POST['stripeToken'],
    'plan' => 'weekly_box'
  ));

  header('Location: thankyou.html');
  exit;
}
catch(Exception $e)
{
  header('Location:oops.html');
  error_log("unable to sign up customer:" . $_POST['stripeEmail'].
    ", error:" . $e->getMessage());
}

Again, we’ve placed a random API key in the code. Replace this with your actual API key to test this code for yourself.

Breaking the code down step-by-step:

  • The first bit of code loads the stripe-php library using Composer.
  • Next, Emma sets the API key to the test secret key for her Stripe account. Note: this is a different key from what she used for Checkout, when she used her test public key.
  • Now, she makes the call to Stripe to create the customer. She includes the ID of the plan, as well as the two parameters received from Checkout: stripeToken and stripeEmail. This single call does several things:
    • Creates a customer
    • Saves the customer’s payment information
    • Signs the customer up for a subscription
    • By default, Stripe bills the customer immediately for their first week of the subscription
  • Emma wants to make sure that even if something goes wrong, her customers have a good experience. So she’s wrapped her call to create the subscription in a try/catch clause. If the call succeeds, she displays a thank you page to the customer. If it fails she logs the error and displays an error page to the customer. (You’ll need to create these representative pages yourself.)

Note that in the interest of keeping this example simple, the submitted form parameters are provided directly to Stripe. In a real environment, you would want to check their validity before using them.

Testing the form

It’s time for Emma to test her code. She copies her files to her webserver and navigates to the signup page in her browser. Since she’s using her test API keys, real credit card numbers won’t work. She instead makes use of Stripe’s numerous test credit cards.

Testing a successful signup

Emma decides to first test a successful sign up. She clicks the “Sign Me Up!” button, enters her email address and one of the test numbers–4242 4242 4242 4242–into Checkout. She makes up a valid expiration date and CVC value for the card, and clicks the “Pay $20.00” button. Everything works and she sees the thank you page.

She goes to her Dashboard to confirm the subscription. After logging in, she confirms her Dashboard is in test mode, clicks on her customers list, and sees the customer that was just created. She clicks on the customer’s email address to view the information page and can see the subscription about half way down the page. Hooray!

Testing errors

Now Emma wants to confirm that if her customer’s card doesn’t work, they will see her error page. This time she enters the number 4000 0000 0000 0341. This is the number of one of Stripe’s test credit card that is designed to throw an error. Checkout will approve this card and generate a token, but she will get an error when she tries to create the subscription. She hits the “Pay $20.00” button and this time instead of being taken to her thank you page, she is redirected to her error page.

In a more realized application, Emma would want to show the actual error returned by Stripe.

Going live

Emma’s tested her form and she’s ready to go live with it. There are three steps she will have to take to move from test to live mode.

First, Emma originally created her plan in test mode, and she’ll need to now create it in live mode. She visits her Dashboard, toggles over to live mode and creates the plan again exactly as she did in test mode. Most importantly, she uses the same plan ID.

Second, Emma modifies her signup form so that her call to Checkout uses her live public key instead of her secret public one:

<script
  src="https://checkout.stripe.com/checkout.js" class="stripe-button"
  data-key="pk_live_XXXXXX"></script>

Third, Emma also changes her create_subscription.php file to use her live secret key:

\Stripe\Stripe::setApiKey("sk_live_XXXXX");

(No actual live secret keys are shown in the above code as secret keys must be kept secret!)

Finally, Emma puts her updated files on her webserver and she’s ready to go!

Further reading