Forums

Stripe payment processing

Hi

I apologise in advance if this is a little rudimentary.

I want to use Python to act as the back end server to process stripe payments from an iPhone app. I have been following an example online that uses the Stripe Python libraries to process the 'test' payment. The problem I'm having is the script in the example works as a CGI file. I have been trying to convert it to a Flask app, but with no success. I do not want it to return a user interface. My iPhone app keeps getting the following error: 'failure Expected status code in (200-299), got 500'. I have not been able to find and figure out a solution.

Here is the original script for the CGI file:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/env python
# -*- coding: UTF-8 -*-

import sys
import json
import cgi
import cgitb
import stripe

cgitb.enable()

print 'Content-Type: text/json'     
print

stripe.api_key = 'your-private-key-goes-here'

json_data = sys.stdin.read()
json_dict = json.loads(json_data)


stripeAmount = json_dict['stripeAmount']
stripeCurrency = json_dict['stripeCurrency']
stripeToken = json_dict['stripeToken']
stripeDescription = json_dict['stripeDescription']

json_response = stripe.Charge.create(amount=stripeAmount, currency=stripeCurrency, card=stripeToken, description=stripeDescription)

print json_response

Here is what I have so far trying to convert it to a Flask app:

import sys
import json
import stripe

from flask import Flask

application = Flask(__name__)

@application.route('/', methods=["POST"])
def payments_test():

    stripe.api_key = 'your-private-key-goes-here'

    json_data = sys.stdin.read()
    json_dict = json.loads(json_data)

    stripeAmount = json_dict['stripeAmount']
    stripeCurrency = json_dict['stripeCurrency']
    stripeToken = json_dict['stripeToken']
    stripeDescription = json_dict['stripeDescription']

    json_response = stripe.Charge.create(amount=stripeAmount, currency=stripeCurrency, card=stripeToken, description=stripeDescription)

    return json_response

Any help will be greatly appreciated.

Well, the indentation doesn't look right in that second listing?

Also, if you're seeing 500 errors, there may be something in the error log, which you'll find on the Web tab?

(as a PS, by convention, we usually put all our imports at the top of a Python file. should make it a little easier to see what the flask/stripe code is actually doing)

The indentation was lost when copying the code into the code snippet. That bit is correct.

I'll move the imports above the 'from flask' line.

The following is taken from the error file, which I believe appeared when I added return json_response at the end of the file:

2014-10-28 13:48:09,899 :Exception on / [POST] Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1687, in wsgi_app response = self.full_dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1360, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1358, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1344, in dispatch_request return self.view_functionsrule.endpoint File "/var/www/dickiebow_pythonanywhere_com_wsgi.py", line 62, in payments_test json_dict = json.loads(json_data) File "/usr/lib/python2.7/json/init.py", line 338, in loads return _default_decoder.decode(s) File "/usr/lib/python2.7/json/decoder.py", line 365, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "/usr/lib/python2.7/json/decoder.py", line 383, in raw_decode raise ValueError("No JSON object could be decoded") ValueError: No JSON object could be decoded

(brief aside: the forum posts use markdown syntax. code listings should be indented by 4 spaces. you can use the little 10101101 icon to do it to blocks of text. hit the "edit" link to edit your old posts)

Anyway, trying to decode that stuff from all the ugly formatting, it looks like the CGI script is trying to get its input from sys.stdin:

json_data = sys.stdin.read()

To get the data sent by the client in flask, you need to use the request object:

from flask import Flask, request
#...

@application.route('/', methods=["POST"])
def payments_test():
    stripeAmount = request.form['stripeAmount']
    #etc

Hi Harry,

Thanks for your help. I have tried to reformat the code snippet above.

The app sends the parameters in as a json object using the post method. The data is not being sent in from a html form.

The form referred to in request.form is just a convention. It doesn't mean that it comes from a literal HTML form. It's just how you get the POST data.

Sorry I wasn't clear in my previous answer. At present I am sending through a json object containing a data dictionary that contains the four value pairs listed above stripeAmount, stripeCurrency, etc... I don't think doing request.form['stripeAmount'] will find the value as it's contained in the json object. I am thinking of changing my app to send the four values through as separate post variables and reference them directly as json doesn't appear to be working very well.

I've made a lot of progress mainly due to the request suggestion above so thank you. The stripe server is now rejecting the payment because I am not using SSL. I have upgraded to a hacker account to add SSL capability. I can't find any instructions on how to add the certificate. Can you let me know how please?

If you're using a webapp at yourusername.pythonanywhere.com, then you get SSL automatically. Just visit https://dickiebow.pythonanywhere.com for example. If you want SSL on your own domain, then you need to get a certificate. There's more info here: https://www.pythonanywhere.com/wiki/SSLOwnDomains

Great, how long after upgrading does it take to come into effect?

It's already enabled, it always was. Visit https://dickiebow.pythonanywhere.com/ and you'll see the little padlock.

It's actually available on free accounts too -- did you confuse "SSL" with "SSH"?

I did mistake the SSH for SSL in the table. However I also need to be able to contact an external website api.stripe.com as part of the payment process. I know it's not on the whitelist for a free account and I thought with a hacker account I had unlimited access to external sites. At present I am getting the error below and I've contacted Stripe support and they have told me that the outgoing server is blocking the request. Can you tell me if that's true please?

2014-11-03 21:34:40,854 :Starting new HTTPS connection (1): api.stripe.com 2014-11-03 21:34:40,897 :Exception on / [POST] Traceback (most recent call last): File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1687, in wsgi_app response = self.full_dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1360, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1358, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/lib/python2.7/dist-packages/flask/app.py", line 1344, in dispatch_request return self.view_functionsrule.endpoint File "/var/www/dickiebow_pythonanywhere_com_wsgi.py", line 82, in payments_test description=stripeDescription File "/usr/local/lib/python2.7/dist-packages/stripe/resource.py", line 259, in create response, api_key = requestor.request('post', url, params) File "/usr/local/lib/python2.7/dist-packages/stripe/api_requestor.py", line 123, in request method.lower(), url, params) File "/usr/local/lib/python2.7/dist-packages/stripe/api_requestor.py", line 209, in request_raw method, abs_url, headers, post_data) File "/usr/local/lib/python2.7/dist-packages/stripe/http_client.py", line 120, in request self._handle_request_error(e) File "/usr/local/lib/python2.7/dist-packages/stripe/http_client.py", line 140, in _handle_request_error raise error.APIConnectionError(msg) APIConnectionError: Unexpected error communicating with Stripe. If this problem persists, let us know at support@stripe.com.

(Network error: ProxyError: Cannot connect to proxy. Socket error: Tunnel connection failed: 403 Forbidden.)

If you've only just upgraded, you may need to hit "reload" on your web app before changes take effect?

The reload worked thanks. It was great to see the test payment in my stripe dashboard, finally. I've added a message to the article I've followed pointing to pythonanywhere. Shame you don't run an affiliate programme, lol.

Here is the link to the article, check the comments section:

http://www.raywenderlich.com/30092/how-to-accept-credit-cards-in-your-ios-apps-using-stripe#comments

Thanks for all the help, I got there in the end.

Actually, we do run an affiliate program! We were just talking this week about how we should activate it for all users. I'll switch it on for you. Check out your "account" tab...