Building a Subscription Signup Form

    Create a subscription signup form using Checkout, and use the Stripe API to complete the signup process.

    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 customers’ 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 Elements to create your own custom payment form, and use 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 product and plan

    The first thing Emma needs to do is create a product and plan in her Stripe account. A plan defines the terms of a customer’s subscription: how much they will be billed and how often. A product can be created using either the Dashboard or the API and a plan can be created in the product detail page or the API.

    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 signup form in which her customers will 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 the customer’s 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 bill the customer for the first interval of the subscription. If billing is successful, Stripe 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">
        src="" class="stripe-button"
        data-name="Emma's Farm CSA"
        data-description="Subscription for 1 weekly box"
        data-label="Sign Me Up!">

    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 is 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, after the form is submitted, to complete the subscription signup.

    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:
    // Be sure to replace this with your actual test API key
    // (switch to the live key later)
      $customer = \Stripe\Customer::create([
        'email' => $_POST['stripeEmail'],
        'source'  => $_POST['stripeToken'],
      $subscription = \Stripe\Subscription::create([
        'customer' => $customer->id,
        'items' => [['plan' => 'weekly_box']],
      if ($subscription->status != 'incomplete')
        header('Location: thankyou.html');
        header('Location: payment_failed.html');
        error_log("failed to collect initial payment for subscription");
    catch(Exception $e)
      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
    • Next, Emma makes sure the first payment on the subscription succeeded by checking the subscription status. If it failed, the subscription will be in an incomplete state that will exipre after 23 hours. Emma can now redirect the customer to a page where she can ask for a different payment method.
    • 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 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 web server 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 sign up

    Emma decides to first test a successful signup. 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 that 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 halfway 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 cards that is designed to throw an error. Checkout will approve this card and generate a token, but the subscription is created in an incomplete status 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 a page where a different payment method can be provided.

    In a more realized application, Emma would want to show the outcome of the charge on the latest_invoice of the given subscription.

    Going live

    Emma has tested her form and she’s ready to go live with it. She will need to take three steps to move from test to live mode.

    First, having originally created her plan in test mode, Emma will need to now create it in live mode. She visits her Dashboard 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:

      src="" class="stripe-button"

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


    (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 web server and she’s ready to go!

    Further reading

    Was this page helpful?

    Thank you for helping improve Stripe's documentation. If you need help or have any questions, please consider contacting support.

    On this page