From time to time I do some pro bono consulting for non-profit organizations and lately I had one such client that I had worked for several years ago reach out to me for advise on setting up a subscription based service solution using PayPal as the payment gateway.
Being forced to reacquaint myself with the solution I wrote for the client almost 4 years ago I realized that there weren’t any “off the shelf” solutions that I could roll into the solution, so I explored PayPal’s API and found that they now offer Recurring Payments and Subscriptions as a service. No sense in recreating the wheel when you can just piggyback off of their product.
Here is a case study that I ran across that really helped me get up and running quickly. Also, be sure to skip down for the sample codes to get you started.
Recurring payments case study
In order to explain this PayPal feature, consider a simple case study. An online service offers customers a monthly subscription for US$10.00 per month. Users may sign up for the service through the online service’s Web site, and each user is assigned a unique account username that serves as an identifier.
With such a service, subscribers would normally be invoiced on a monthly basis. To understand how this would work with PayPal’s Subscriptions And Recurring Payments feature, consider the following process flow:
- The user (let’s name him Sam Subscriber) arrives at the service Web site to sign up and, after entering and saving the required profile information, is assigned a unique username. Sam can then either try the service out for free (if a free trial is available) or immediately sign up for paid service. The latter is accomplished by hitting a clearly-visible Subscribe button.
- The Subscribe button is actually an entry point into the PayPal system. On clicking it, Sam is redirected to the PayPal Web site, where he can either log in to an existing account or create a new one. This is because, to use PayPal to send or receive money, both parties in the transaction must have PayPal accounts; PayPal does not process payments between non-PayPal parties (for this same reason, the service provider must have a business account with PayPal to receive payments). Account signup is free.
The Subscribe button is preprogrammed with certain important informationâ€"the service provider’s account details on PayPal, the billing cycle and amount, and the currency in which the payment is to be billed. This tells the PayPal system how much money is to be billed, how often, and where to send it. Since Sam’s account name at PayPal may not necessarily match his newly-minted account on the service provider’s site, the account username assigned to Sam is also passed to PayPal to simplify reconciliation later.
- Once Sam authorises the PayPal payment, an e-mail containing details about the transaction is dispatched to the service provider (who also has a PayPal account, remember). The provider then logs in, checks that the payment has been received, and activates paid service for Sam. The account username passed to PayPal also appears in the e-mail, and helps the service provider identify which user made the payment and thus activate the correct account.
- Because the first payment took place through PayPal’s Subscriptions And Recurring Payments, PayPal automatically keeps track of the billing cycle stated at the time of first payment, and rebills Sam on a monthly basis until Sam manually cancels his subscription. The service provider receives e-mail notification of payment from PayPal on a monthly basis, and thus keeps Sam’s service alive until a cancellation notice arrives from PayPal.
This recurring payment process is completely automatic, and requires no intervention from either Sam or the service provider.
Programming the PayPal button
As a service provider interested in offering customers a subscription service via PayPal, the first step for you is to acquire a PayPal account. This is pretty simple: drop by the PayPal Web site and sign up for a Business Account. Then log in to your new account and navigate to the Subscriptions And Recurring Payments option. The resulting page allows you to specify various parameters for the subscription:
- Subscription Name: A descriptive name for the service/item that a user will sign up for
- Reference Item: A reference number or code that you can use for internal tracking purposes
- Subscription Price: The amount to be billed
- Length of the Billing Cycle: The period (days, weeks, months or years) over which subscribers are to be billed
- Once you’ve filled in all the data, choose a PayPal button to display on your Web site. If needed, you can even allow users a free trial period or give them a link to cancel their subscription if they’re not satisfied.
Examples:
Listing A shows what the button code, generated by PayPal from the basic information you provided, might look like.
1: <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
2: <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but20.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
3: <input type="hidden" name="cmd" value="_xclick-subscriptions">
4: <input type="hidden" name="business" value="[email protected]">
5: <input type="hidden" name="item_name" value="My Special Service">
6: <input type="hidden" name="item_number" value="SS-001">
7: <input type="hidden" name="no_note" value="1">
8: <input type="hidden" name="currency_code" value="USD">
9: <input type="hidden" name="a3" value="10.00">
10: <input type="hidden" name="p3" value="1">
11: <input type="hidden" name="t3" value="M">
12: <input type="hidden" name="src" value="1">
13: <input type="hidden" name="sra" value="1">
14: </form>
When placed on your Web site, this code generates a PayPal button which links into the PayPal payment system. You should place this code somewhere on your How To Pay page. But before you do that, you need to add one more field to the automatically-generated code…a hidden field that contains the subscriber’s username. This field will be dynamically populated at runtime by your Web site.
Assuming you’ve got a PHP site and store your user’s account name in a session variable called username, Listing B shows what the updated code for the PayPal button would look like.
1: <form action="https://www.paypal.com/cgi-bin/webscr" method="post">
2: <input type="image" src="https://www.paypal.com/en_US/i/btn/x-click-but20.gif" border="0" name="submit" alt="Make payments with PayPal - it's fast, free and secure!">
3: <input type="hidden" name="cmd" value="_xclick-subscriptions">
4: <input type="hidden" name="business" value="[email protected]">
5: <input type="hidden" name="item_name" value="My Special Service">
6: <input type="hidden" name="item_number" value="SS-001">
7: <input type="hidden" name="no_note" value="1">
8: <input type="hidden" name="currency_code" value="USD">
9: <input type="hidden" name="a3" value="10.00">
10: <input type="hidden" name="p3" value="1">
11: <input type="hidden" name="t3" value="M">
12: <input type="hidden" name="src" value="1">
13: <input type="hidden" name="sra" value="1">
14: <input type="hidden" name="custom" value="<?php echo $_SESSION['username']; ?>">
15: </form>
Once a subscriber logs in to your Web site, his or her username will be stored in a PHP session variable for use where required. On the How To Pay page, this session variable is used to dynamically populate the hidden field inside the PayPal button. The advantage of this little modification: since PayPal will now incorporate the additional username information in all its notifications and e-mails pertaining to the transaction, you, as the service provider, will be able to clearly distinguish between different users and transaction records.
In case you’re wondering what all the other fields are, they’re related to the subscription period, bill amount, and billing frequency. Look in the PayPal manual for a complete explanation of each variable.
When a subscriber clicks the button generated by the code above, the username is transferred to PayPal along with the billing details. Once the subscriber completes the PayPal payment process, an e-mail receipt is generated and sent to the subscriber, and an e-mail payment notification is generated and sent to you, the service provider. You can then activate paid service for the subscriber, matching the payment with the subscriber through the unique username that PayPal supplies from the button’s Custom field.
Now, while the process above is fairly simple and works well in practice, it has one fatal flaw: It requires you, as the service provider, to manually perform the task of reading PayPal’s e-mail and activating each subscriber account. As your subscriber base increases, such manual account activation becomes less feasible, especially if you’d prefer to take all the money you’re making and go to the Bahamas for a week. And that’s where IPN comes in.
Integrating IPN With subscriber payments
IPN, which stands for Instant Payment Notification, is PayPal’s automated notification system for payments. Once you begin using IPN, you can completely alter the way you deal with subscriber accounts, replacing the earlier manual process with an automated one. This is because IPN sends you a signal every time you receive a subscriber payment or when a subscriber cancels a subscription; you can then intercept this signal and write code to "do something" with it, such as automatically activating or deleting a subscriber account.
To enable IPN for your Business Account on PayPal, simply visit your account on the PayPal Web site and turn the feature on. As part of this process, you also need to supply PayPal with the URL to a script on your Web site; this is the script PayPal will invoke every time it generates an IPN, and this script must therefore be capable of trapping IPN signals and taking appropriate action based on each.
IPN signals can be intercepted by scripts written in most common Web development languages, including ASP.NET, PHP, and Perl. Take a look at the PHP pseudo-code in Listing C, which shows you how such a script might work.
1: <?php
2:
3: // define array to store PayPal request
4: // as key-value pair
5: $postvars = array();
6:
7: // read post from PayPal into local array while (list ($key, $value) = each ($HTTP_POST_VARS)) {
8: $postvars[] = $key;
9: }
10:
11: // add a 'cmd' parameter to the parameter list that is POSTed // back, as required by PayPal $req = 'cmd=_notify-validate';
12:
13: // append each parameter posted by the PayPal // as name value pair to the "req" variable for ($var = 0; $var < count ($postvars); $var++) {
14:
15: $postvar_key = $postvars[$var];
16: $postvar_value = $$postvars[$var];
17: $req .= "&" . $postvar_key . "=" . urlencode ($postvar_value); }
18:
19: // post the request back to PayPal system to validate $header .= "POST /cgi-bin/webscr HTTP/1.0rn"; $header .= "Content-Type: application/x-www-form-urlencodedrn";
20: $header .= "Content-Length: " . strlen ($req) . "rnrn";
21:
22: // open file pointer to the paypal server $fp = fsockopen ("www.paypal.com", 80, $errno, $errstr, 30);
23:
24: if (!$fp) {
25: // HTTP error
26: // log an error
27: } else {
28:
29: // POST the data using the file pointer created above
30: fputs ($fp, $header . $req);
31:
32: while (!feof($fp)) {
33:
34: // read the response from the PayPal server
35: $res = fgets ($fp, 1024);
36:
37: // check if the request has been VERIFIED by PayPal
38: // if it is, then you can proceed further
39: // if it is INVALID, then abort the process
40: if (strcmp ($res, "VERIFIED") == 0) {
41:
42: // get the value stored in the "custom" field
43: // (username) in a local variable
44: $username = $HTTP_POST_VARS["custom"];
45:
46: // check if the username sent with the PayPal IPN request exists in the database
47: // using a custom function called userExists()
48: if(userExists($username)) {
49:
50: // check the transaction type for the subscription sent by PayPal
51: // and take action accordingly
52: if(isset($HTTP_POST_VARS["txn_type"]) &&
53: strtolower($HTTP_POST_VARS["txn_type"]) == "subscr_payment") {
54:
55: // a subscriber just paid
56: // increase the subscription period by X days
57:
58: } else {
59:
60: // incorrect transaction type
61: // log an error
62:
63: }
64:
65: }
66:
67: } else if (strcmp ($res, "INVALID") == 0) {
68:
69: // an INVALID transaction
70: // log an error
71:
72: }
73:
74: }
75:
76: }
77: ?>
78:
This looks pretty complicated, but it’s actually not. The first bit of the code involves verifying that the IPN is actually from PayPal and not from a hacker trying to break into the payment system. This verification is accomplished using a standard process outlined in PayPal’s IPN manual, reposting the entire request back to PayPal, and using the encrypted key within it to check the source of the request. Look in the PayPal IPN manual for more on how this authentication system works.
Assuming the response is VERIFIED, you can go ahead and process the data sent by PayPal in the IPN. First, extract the value of the "custom" variable the subscriber’s username"and check that the subscriber actually exists in your system. If the test is successful and the named subscriber does hold an account with your service, proceed to handle the txn_type field, which contains information on the PayPal transaction that generated the IPN.
In the context of subscription payments, the txn_type field may contain any of the following values:
- subscr_signup – a subscriber has signed up for the service
- subscr_payment – a subscriber has paid for the service
- subscr_failed – a subscriber tried to pay for the service but things didn’t work out
- subscr_cancelled – a subscriber cancelled a subscription
- subscr_eot – a subscriber has reached the end of the subscription term
- subscr_modify – a subscriber profile has been modified
Most of the time, you only need to be concerned with the subscr_payment type this indicates that a payment has been made to your PayPal account. On receipt of this signal, the script can immediately (and automatically) update your subscription database, and activate paid service for the subscriber. You may also be interested in intercepting the subscr_cancelled and subscr_eot signals, to update your database with the change in subscriber state.
This automated process does away with the need for manual processing of PayPal e-mails. The script above automatically intercepts payment notifications via the IPN service, and turns a subscription "on" or "off" depending on the contents of the notification. As with the manual process outlined previously, the Custom field with the subscriber’s username is used throughout for reconciliation and tracking. Try it out for yourself, and you’ll quickly see how valuable it is.
I found this excellent case study and sample code here: Integrate your online service with PayPal – Web Development – Builder AU
Questions or Comments?