Paypal IPN on GAE

Selling digital goods with Paypal IPN on Google App Engine

Let's say you're selling e-books or software with Paypal. It is trouble to have to handle each order manually. A better way is, tell Paypal to notify you for each order by posting the transaction's data to a URL you specified. The idea is that you can set up a web application on Google App Engine to handle that request, such as emailing a link to the customer automatically. For security, that link is usable for a certain period only (say two days).

Here is such a package. It is based on the DigiSell PHP script by NGCoders. It has been rewritten in Scala and now works on Google App Engine (so, it can be set up and used for free). It should also run on any standard Java servlet container (e.g., Tomcat, Jetty) even though I haven't tested that. You don't need to know Scala nor do any programming to use it. The code is licensed under GPL and can be downloaded here: binary and source.

How to use

  1. Create a free account on Google App Engine (GAE).
  2. In the main page of GAE, create an application. Give it any name you'd like (e.g., digisell4foo).
  3. Download this file and unzip it into any folder you'd like (e.g., c:\digisell-scala). Then you will get a c:\digisell-scala\war folder.
  4. Edit the appengine-web.xml file in c:\digisell-scala\war\WEB-INF to put your GAE application name there:
    <appengine-web-app ...>
      <application>digisell4foo</application>
      ...
    </appengine-web-app>
  5. Edit the settings.xml file in c:\digisell-scala\war\WEB-INF to put your Paypal login email address and the currency you use in Paypal for your products. These information must be correct otherwise it won't work :
    <config
        
    seller-paypal-login-email = "kent@foo.com"
        currency="USD"
        ...>
        ...
    </config>
  6. In the same file, set the email address of your Google account (you used to log in to GAE). This will be used as the From address when sending emails to the customer and to yourself. If you set it incorrectly, GAE will NOT send the mail!
    <config
        ...
        from-email="kent.tong.mo@gmail.com" 
    ...>
        ...
    </config>
  7. Set the random secret used to encrypt the download link (so that people can't guess the link to download the files), the validity of the download link in hours (so that sharing the link on the net is not useful) and the reply-to email address:
    <config
        ...
        secret="cgmb56u9vuihi2e1h68579"
        download-life="48"
        reply-email="support@foo.com"
     ...>
    </config>
  8. Specify the digital products you sell. For each product, you must use the same item ID and price you used to create the "buy now" button on Paypal. When the application receives the notification initiated by the buy now button, it will compare the item ID, the price, the currency and your Paypal login email to those in the notification for an exact match. If there is anything wrong, it will fail and will not delivery the digital goods to the buyer! This is to ensure that the buyer is paying the right price for the right product from the right seller (you). In the example below, it is assumed that the digital goods are file1.pdf and file2.pdf:
    <config ...>
        ... 
        <products>
            <product id="p-123" name="book 1" price="19.95" path-in-web-inf="file1.pdf"></product>
            <product id="p-124" name="book 2" price="3.50" path-in-web-inf="file2.pdf"></product>
        </products>
    </config>
  9. Copy the file1.pdf and file2.pdf into the c:\digisell-scala\war\WEB-INF folder, so that they can be served by the application.
  10. Set the subject and content of the email the buyer will receive. You can use placeholders such as {first_name} to mean the first name of the buy and etc.:
  11. <config ...>
        <buyer-email subject="Thank you for buying {product_name}" >
    Hello {first_name} {last_name},

    Thank you for buying {product_name}. Here is your download link - 
    {product_link}. 
    This link will remain valid for {download_life} hours.
        </buyer-email>

        ...
    </config>
  12. Set the To-address (your own email address), subject and content of the email you would like to receive for each order. Again, you can use placeholders:
    <config ...>
        <seller-email to="kent@foo.com" subject="Product Sale Notification for {product_name}" >
    Hello Sir,

    This mail is to notify you about the sale of {product_name} whose product id is {product_id}.
    The sale was made to {first_name} {last_name} ({payer_email}) at {date}.
        </seller-email>

        ...
    </config>
  13. Download the GAE SDK for Java from GAE. Let's say it has been placed into c:\appengine-java-sdk. Run the following command to upload the application to GAE:
      c:\appengine-java-sdk\bin\appcfg.cmd update c:\digisell-scala\war
  14. Now you need to tell Paypal to notify your GAE application for each order. To do that, log into the Paypal and choose My Account | Profile | Other Options | Selling Tools, then enable "Instant payment notifications" and set the URL to http://digisell4foo.appspot.com/digisell. Another way to do it is to add a parameter to each "buy now" button:
    <form action="..." method="post">
      <input type="hidden" name="notify_url" value="http://digisell4foo.appspot.com/digisell">
      ...
    </form>
  15. That's it! You can check the log on GAE to check if it is working. However, if you'd like to place an order to test it before a real buyer hits it, please read on.

Testing in the Paypal sandbox

Before using it in production, you should really test it. Paypal provides a sandbox environment that behaves just like the production one but of course with fake data. To use it to test your setup:
  1. Create a free account in the Paypal developer website.
  2. Use that account to log in. Then use the "preconfigure account" function to create two test accounts: one as a seller and one as a buyer. These two accounts only exist in the sandbox. Only their emails and passwords are significant.
  3. Enter the sandbox test website as the fake seller. Create a "buy now" button as usual. Paste the code into a local HTML file. Add the notify_url parameter as below. Note that there is an extra parameter added. This is because the application needs to validate each notification with the Paypal server to confirm that it is genuine. Here, this extra parameter tells the application to validate with the Paypal sandbox server instead of the real Paypal server:
    <form action="..." method="post">
      <input type="hidden" name="notify_url" value="http://digisell4foo.appspot.com/digisell?sandbox=1">
      ...
    </form>
  4. Open that HTML file and click the "buy now" button. Log in as that fake buyer. Complete the order.
  5. If everything works, you should receive the seller email notification at the address specified at <seller-email to="xxx">. As the email addresses in the two test accounts are fake, those addresses don't exist and thus won't receive any real emails.
  6. Click on the download link in that email and you should be able to download.

Getting the source code

If you'd like to modify it, please download the complete Eclipse project folder. Just install the Google plugin for Eclipse and the Scala Eclipse plugin. and then you can import it into Eclipse and start working.