Get the Powers to Act from Fresh Ideas

December 23, 2012

PayPal IPN, Google App Engine, Python Integration, an Example


1. PayPal IPN Python Code from Django Aware blog.
2. A Google Group discussion

3. Pro PayPal E-Commerce. I recommend this book.
4. Professional Web APIs with PHP. This book is good for non-PayPal stuffs too. A good book.

My Tutorial

(1) Make a sandbox/testing account with PayPal.
(2) Log in to that account. Get to IPN Simulator at the bottom of the page.
(3) In the form that shows up, make sure
1. notify url =
2. "receiver_email" = "ACCOUNT_EMAIL" that you use in your IPN handler code.
3. You should vary "payment_status" from "Completed" to "Failed" to "Pending" etc.
Send the form a few times.
(4) Paypal says it can't send.
Change " notify url" to etc. You get the same failure result.
It is as expected: you haven't written the code to handle this POST request.

The code you need to write is:

import os import sys import logging import wsgiref.handlers from google.appengine.ext import webapp from google.appengine.ext.webapp import template from util.sessions import Session from google.appengine.ext import db sys.path.append(os.path.join(os.pardir,os.getcwd())) from helper_rendering import doRender import urllib, urllib2 from google.appengine.api import mail from google.appengine.api import urlfetch from google.appengine.ext.webapp.util import run_wsgi_app PP_URL = "" ACCOUNT_EMAIL= "" #PP_URL = "" #ACCOUNT_EMAIL = "" class IPNHandler1(webapp.RequestHandler): def post(self): parameters = None # Check payment is completed, not Pending or Failed. if self.request.get('payment_status') == 'Completed': if self.request.POST: parameters = self.request.POST.copy() if self.request.GET: parameters = self.request.GET.copy() logging.debug('IPN 1, or your own message for yourself to read in log.') else: self.response.out.write('Error, sorry. The parameter payment_status was not Completed.') # Check the IPN POST request came from real PayPal, # not from a fraudster. if parameters: parameters['cmd']='_notify-validate' params = urllib.urlencode(parameters) status = urlfetch.fetch( url = PP_URL, method = urlfetch.POST, payload = params, ).content if not status == "VERIFIED": self.response.out.write('Error. The request could not be verified, check for fraud.') parameters['homemadeParameterValidity']=False # parameters = None # You may log this data in your database, # for later investigation. # Check the money is really to go to your account, # not to a fraudster's account. if parameters['receiver_email'] == ACCOUNT_EMAIL: transaction_id = parameters['txn_id'] # Check if this is a new, unique txn, # not a fraudster re-using an old, verified txn. invoice_id = parameters['invoice'] currency = parameters['mc_currency'] amount = parameters['mc_gross'] fee = parameters['mc_fee'] # Check if they are the right product/item, right price, # right currency, right amount, etc. email = parameters['payer_email'] identifier = parameters['payer_id'] # Email/notify/inform the user for whatever reason. parameters['your_parm']= "It is ok on 19 September, 2010." logging.debug('IPN 100. All OK.') logging.debug(parameters['txn_id']) logging.debug(parameters['invoice']) logging.debug(parameters['payer_email']) # With this IPN testing, you can't see results on the browser. # See results on the log file maintained by Google AppEngine. #template_values = { 'params': parameters, } #doRender(self,'ipn_ok.htm', template_values ) if __name__ == '__main__': print "IPNHandler1 is being run as main()."

(1) Now send the IPN Simulator form again as explained in the beginning of this post.
Now Paypal says it has sent it successfully.
(2) Log in to your Google AppEngine developer account.
Get to the log. Set logging level to "debug"
Check the log entries. you will see something like:

1. 09-29 01:54AM 28.745 /ipn_handle1 200 2141ms 408cpu_ms 4kb gzip(gfe) See details - - [29/Sep/2010:01:54:30 -0700] "POST /ipn_handle1 HTTP/1.1" 200 4842 - "gzip(gfe)" "" ms=1234 cpu_ms=123 api_cpu_ms=0 cpm_usd=0.123456 loading_request=1 2. D 09-29 01:54AM 29.395 IPN 1 3. D 09-29 01:54AM 30.682 IPN 100. All OK. 4. D 09-29 01:54AM 30.682 31929814 5. D 09-29 01:54AM 30.682 abc1234 6. D 09-29 01:54AM 30.682 7. I 09-29 01:54AM 30.705 Creating session session-575150356408086346 8. I 09-29 01:54AM 30.884 This request caused a new process to be started for your application, and thus caused your application code to be loaded for the first time. This request ...

If you have any question, just ask by way of commenting below.


  1. Wow, wonderful blog format! How lengthy have you been
    blogging for? you make running a blog glance easy. The full look of your site is wonderful, as
    well as the content material!
    Also visit my web blog ... i need to make more money

  2. I couldn't resist commenting. Well written!
    Also see my webpage > Online Casinos That

  3. Hmm is anyone else experiencing problems with the pictures on
    this blog loading? I'm trying to figure out if its a problem on my end or if it's the blog.
    Any feed-back would be greatly appreciated.
    Review my site ... slots for money

    1. Thank you very much.
      I've reduced images on my blog from now on.

  4. Admiring the commitment you put into your website and in depth
    information you provide. It's nice to come across a blog every once in a while that isn't the same unwanted rehashed information.

    Great read! I've saved your site and I'm adding your
    RSS feeds to my Google account.
    Feel free to visit my homepage ; slots for real money

  5. Thank you so much for this code snippet. This gave a great start into writing my own IPN Handler code. I searched high and low on the internet to find a solution for running IPN PayPal payments on a google site which does not support server side scripting. Then I figured out that Google App Engine would be the place to host my app/listener. Stranger to Python that I am, I found your website as I was googling around. I cannot thank you enough for this. By the way, even the Integration Support team at PayPal did not suggest that I could run a IPN listener on GAE. On the PayPal developer website, the code samples for IPN only include PHP, Java,ASP.Net but no mention of Python on GAE. I would definitely want to contact them and refer them to your blog so that if can benefit more people.

    BTW, I had to add the following code to register the IPN Handler with the webapp framework and invoke it.
    def main ():
    application = webapp.WSGIApplication ([('/',IPNHandler1)], debug=True)
    run_wsgi_app (application)

    if __name__ == '__main__':
    print "IPNHandler1 is being run as main()."
    main ()

  6. Thanks alot Kyaw! Appreciate the code (ps I am a real person).

  7. AnonymousMay 20, 2014

    How would this change for webapp2?

  8. I can't manipulate the data in the db within this function ! can you please show me how to do it ? I'd really appreciate it !