Quick start

From scratch

To integrate itemshop into your app, you need to add the ItemBP blueprint to your application, and create some templates with a bit of javascript to handle the form:

  • application code
    • instantiate an ItemBP object with: a unique name, a stripe.Charge (one-time) or stripe.Customer (recurring) payment, and some default arguments for the payment (e.g. the price)
    • mount the item blueprint on your app using app.register_blueprint(item.blueprint, **options)
  • HTML and JS
    • create a template called “itemshop/default_index.html”, which contains a form with credit card fields and one hidden field called “stripe_token
    • wire up the stripe.js API with this form, so that when the user submits the form, their credit card is processed with stripe.js, and your stripe_token hidden field is populated with the token returned by stripe
    • create a template called “itemshop/default_process.html”, which will be shown to the user after their purchase is complete

The sections below will go into more detail about each of these steps. You can also re-use the demo code found in the source repo.

Re-using the demo code

You can copy from the demos that most closely match what you are trying to do. First, clone the source repo:

hg clone https://bitbucket.org/lost_theory/flask-stripe-blueprint/

Then, to integrate one of the demos into your app:

  1. copy over the static CSS, JS, images from demos/static into your app’s static directory
  2. copy over the templates in the “itemshop” directory to your app’s template directory
  3. copy over the code in app.py that instantiates the ItemBP, then mount the blueprint on your app

From scratch, step-by-step

App code: skeleton

itemshop was designed to be integrated into an existing app, so let’s grab the sample app from flask’s home page.

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello():
    return "Welcome to my item shop."

if __name__ == "__main__":
    app.run(use_debugger=True, use_reloader=True)

App code: ItemBP

Now, at the top of app.py, we need to import the stripe library, the itemshop library, and set the stripe API key:

import itemshop
import stripe
stripe.api_key = 'UwK0UE4tdPGNJckqfiu5UbzUJxHClRjW'

Now let’s instantiate the ItemBP object by passing in three arguments:

item = itemshop.ItemBP('my_item', stripe.Charge, dict(
    amount=1500,
    currency='usd',
))
  1. First, a unique ID 'my_item'
  2. Next, we pass in the stripe payment object to use:
  • stripe.Charge is used for one-time payments, all it needs is an amount to charge
  • stripe.Customer is used for recurring payments, it needs a plan argument, which is created through the stripe web interface (e.g. plan='silver' might correspond to a monthly charge of $10.00)
  1. Finally, we pass in a dict of default values that will be used to instantiate the stripe payment. In this case, we pass in the amount (1500 in cents = $15.00) and the currency ‘usd’. Any other values, like the stripe_token will come from the form data. You can also use this dict to pass in an api_key, which will override the global stripe.api_key.

After that, all you need to do is mount the blueprint on your app using register_blueprint:

app.register_blueprint(item.blueprint)

By default, this will mount the blueprint onto the root of your app (“/”). Let’s mount the blueprint somewhere else, so we don’t override the existing view at “/”. To do this, use url_prefix:

app.register_blueprint(item.blueprint, url_prefix="/shop")

Now, run your application:

$ python app.py
 * Running on http://127.0.0.1:5000/
 * Restarting with reloader...

Go to “/shop” in your browser and you should see an error page, because the template is missing. That means it’s time for the next step!

HTML

Now we need to create the template that contains the credit card form.

In the <head>, include the following Javascript:

<script type="text/javascript" src="https://js.stripe.com/v1/"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script type="text/javascript" src="/static/demo.js"></script>

<script type="text/javascript">
    Stripe.setPublishableKey('pk_uo5x4qcbsPsrDy6dBosrq1Ykub53C');
</script>

We are using the stripe.js API library, jQuery, a demo.js file we’ll define in a bit, and setting our Stripe account’s public key. The key in that example (pk_uo5...) is my test key, please try to use your own if you have one.

Next, we’ll include some item details in the body of the page:

<h1>{{item.name}}</h1>

<p>
    Please fill out the form below to complete your purchase for {{item.name}}.
    {% if item.price %}
        The price is ${{item.price}}.
    {% else %}
        This is a subscription.
    {% endif %}
</p>

Next, we’ll use a hidden div to contain the validation message when the stripe API rejects the payment:

<div id="fail" style="display: none; color: red;">
    Sorry, we could not process your credit card: <span id="fail_reason"></span>.
    <br/><br/>
    Please correct the form and try again.
</div>

Now we create the purchase form:

<form id="stripe-form" action="{{url_for('itemshop.%s.process' % item.name)}}" method="POST">
    <input type="hidden" name="stripe_token" value="" />
    <div>
        <label>Email</label>
        <input type="text" size="20" maxlength="99" name="email" />
    </div>
    <div>
        <label>Card number</label>
        <input type="text" size="20" maxlength="20" autocomplete="off" id="card-number"/>
    </div>
    <div>
        <label>CVC</label>
        <input type="text" size="4" maxlength="4" autocomplete="off" id="card-cvc"/>
    </div>
    <div>
        <label>Expiration (MM/YYYY)</label>
        <input type="text" size="2" maxlength="2" id="card-expiry-month"/>
        /
        <input type="text" size="4" maxlength="4" id="card-expiry-year"/>
    </div>

    <div>
        <button type="submit" class="submit-button">Submit Payment</button>
    </div>
</form>

Two important things to note:

  1. The very first field is the hidden field for “stripe_token”. We will use this element to store the token obtained from the stripe.js API call.
  2. None of the credit card fields (card number, CVC, expiration month, or expiration year) have a name attribute. This means that even if the form gets submitted without javascript, the credit card fields will not be sent to your backend. This is a safety precaution.

The last step for the HTML templates is to create the “thanks” template, default_process.html, which is what gets shown to users after they successfully make a purchase. It could be as simple as this:

<html>
<head>
<title>Thank you</title>
</head>
<body>

<h1>Thank you!</h1>

<div>
    <p>Thank you for purchasing {{item.name}}!</p>

    <p>
        <a href="{{url_for('itemshop.%s.index' % item.name)}}">Back</a> to order form.</a><br />
    </p>
</div>

</body>
</html>

Now we need to write the javascript to process the credit card form.

Javascript

Create a new static JS file at static/demo.js (you could also just put this in a <script> tag in default_index.html).

First, we attach an on-submit handler to the “#stripe-form” form tag:

$(document).ready(function() {
    $("#stripe-form").submit(function(event) {
        // disable the submit button to prevent repeated clicks
        $('.submit-button').attr("disabled", "disabled");
        $("#fail").hide('fast');

        var amount = 0;
        Stripe.createToken({
            number: $('#card-number').val(),
            cvc: $('#card-cvc').val(),
            exp_month: $('#card-expiry-month').val(),
            exp_year: $('#card-expiry-year').val()
        }, amount, stripeResponseHandler);

        // prevent the form from submitting with the default action
        return false;
    });
});

When the user clicks the submit button (or presses Enter on their keyboard), we first disable the submit button (to prevent repeated form submissions going through), and re-hide the failure message div (in case it was already showing). We then make the stripe.js API call, Stripe.createToken. Note that the values are pulled out of the form fields using CSS element IDs (#card-number, #card-cvc, etc.), not with name attributes. We set the amount to 0 when we create the token, because we will pass the real value from the server-side code. The stripeResponseHandler function is a callback, which we will define next. Finally, we return false to prevent the default form action, which would have POSTed the form to the flask app.

function stripeResponseHandler(status, response) {
    if(status == 200) {
        $("input[name=stripe_token]").val(response.id);
        $("#stripe-form button").removeAttr('disabled');
        $('#stripe-form').off("submit");
        $("#stripe-form").submit();
    } else {
        $("#fail").show('fast');
        $("#fail_reason").html(response.error.message);
        $("#stripe-form button").removeAttr('disabled');
    }
}

The stripeResponseHandler callback does a check on the status of the stripe API call:

  • If the response was 200, then the credit card is valid and a token was returned as response.id. We store that token in the stripe_token field, re-enable the submit button, turn off the on-submit handler, then submit the form, which will POST the form data to the flask app.
  • If anything other than 200 status was returned, then there was an error, so we pull the error out of the repsonse at response.error.message, stuff it into the #fail_reason span, show the #fail div, then re-enable the submit button so the user can correct the form and try again.

Now you’re ready to start making some (test) money!

Test it out

Go back to http://127.0.0.1:5000/shop and use the following test values on the form:

  • Credit card: 4242-4242-4242-4242
  • CVC: any 4 digit number
  • Expiration date: any date in the future

You should get the “Thank you” page. Go to your stripe dashboard, switch to test mode, and you should see the charge recorded.

Also try with some bad values (blank fields, invalid credit card, past expiration date), to see what errors are shown on the form.

Congrats! You’ve earned your first (test) dollar!

Where to go from here? Clone the repository and check out the demos for more advanced usage (multiple items, receipt codes, retrieving payments from the stripe API, etc.).

itemshop

Table Of Contents

Related Topics

This Page