Accepting credit card payments

There are multiple ways to accept credit card payments online. web2py provides specific APIs for some of the most popular and practical ones:

The first two mechanisms above delegate the process of authenticating the payee to an external service. While this is the best solution for security (your app does not handle any credit card information at all) it makes the process cumbersome (the user must login twice; for example, once with your app, and once with Google) and does not allow your app to handle recurrent payments in an automated way.

There are times when you need more control and you want to generate yourself the entry form for the credit card info and than programmatically ask the processor to transfer money from the credit card to your account.

For this reason web2py provide integration out of the box with Stripe, Authorize.net (the module was developed by John Conde and slightly modified) and DowCommerce. Stripe is the simplest to use and also the cheapest for low volume of transactions (they charge no fix cost but charge about 3% per transaction). Authorize.net is better for high volumes (has a fixed yearly costs plus a lower cost per transaction).

Mind that in the case of Stripe and Authorize.net your program will be accepting credit cards information. You do not have to store this information and we advise you not to because of the legal requirements involved (check with Visa or MasterCard), but there are times when you may want to store the information for recurrent payments or to reproduce the Amazon one-click pay button.

Google Wallet

The simplest way to use Google Wallet (Level 1) consists of embedding a button on your page that, when clicked, redirects your visitor to a payment page provided by Google.

First of all you need to register a Google Merchant Account at the url:

  1. https://checkout.google.com/sell

You will need to provide Google with your bank information. Google will assign you a merchant_id and a merchant_key (do not confuse them, keep them secret).

Then you simply need to create the following code in your view:

  1. {{from gluon.contrib.google_wallet import button}}
  2. {{=button(merchant_id="123456789012345",
  3. products=[dict(name="shoes",
  4. quantity=1,
  5. price=23.5,
  6. currency='USD',
  7. description="running shoes black")])}}

When a visitor clicks on the button, the visitor will be redirected to the Google page where he/she can pay for the items. Here products is a list of products and each product is a dictionary of parameters that you want to pass describing your items (name, quantity, price, currency, description, and other optional ones which you can find described in the Google Wallet documentation).

If you choose to use this mechanism, you may want to generate the values passed to the button programmatically based on your inventory and the visitor shopping chart.

All the tax and shipping information will be handled on the Google side. Same for accounting information. By default your application is not notified that the transaction has been completed therefore you will have to visit your Google Merchant site to see which products have been purchased and paid for, and which products you need to ship to your buyers there. Google will also send you an email with the information.

If you want a tighter integration, you have to use the Level 2 notification API. In that case you can pass more information to Google and Google will call your API to notify about purchases. This allows you to keep accounting information within your application but it requires you expose web services that can talk to Google Wallet.

This is a considerable more difficult problem but such API has already been implemented and it is available as plugin from

  1. http://web2py.com/plugins/static/web2py.plugin.google_checkout.w2p

You can find the documentation of the plugin in the plugin itself.

Paypal

Paypal integration is not described here but you can find more information about it at this resource:

  1. http://www.web2pyslices.com/main/slices/take_slice/9

Stripe.com

This is probably one of the easiest way and flexible ways to accept credit card payments.

You need to register with Stripe.com and that is a very easy process, in fact Stripe will assign you an API key to try even before you create any credentials.

Once you have the API key you can accept credit cards with the following code:

  1. from gluon.contrib.stripe import Stripe
  2. stripe = Stripe(api_key)
  3. d = stripe.charge(amount=100,
  4. currency='usd',
  5. card_number='4242424242424242',
  6. card_exp_month='5',
  7. card_exp_year='2012',
  8. card_cvc_check='123',
  9. description='the usual black shoes')
  10. if d.get('paid', False):
  11. # payment accepted
  12. elif:
  13. # error is in d.get('error', 'unknown')

The response, d, is a dictionary which you can explore yourself. The card number used in the example is a sandbox and it will always succeed. Each transaction is associated to a transaction id stored in d['id'].

Stripe also allows you to verify a transaction at a later time:

  1. d = Stripe(key).check(d['id'])

and refund a transaction:

  1. r = Stripe(key).refund(d['id'])
  2. if r.get('refunded', False):
  3. # refund was successful
  4. elif:
  5. # error is in d.get('error', 'unknown')

Stripe makes very easy to keep the accounting within your application.

All the communications between your app and Stripe go over RESTful web services. Stripe actually exposes even more services and provides a larger set of Python API. You can read more on their web site.

Authorize.Net

Another simple way to accept credit cards is to use Authorize.Net. As usual you need to register and you will obtain a login and a transaction key (transkey. Once you have them it works very much like Stripe does:

  1. from gluon.contrib.AuthorizeNet import process
  2. if process(creditcard='4427802641004797',
  3. expiration="122012",
  4. total=100.0, cvv='123', tax=None, invoice=None,
  5. login='cnpdev4289', transkey='SR2P8g4jdEn7vFLQ', testmode=True):
  6. # payment was processed
  7. else:
  8. # payment was rejected

If you have a valid Authorize.Net account you should replace the sandbox login and transkey with those of your account, set testmode=False to run on the real platform instead of the sandbox, and use credit card information provided by the visitor.

If process returns True, the money has been transferred from the visitor credit card account to your Authorize.Net account. invoice is just a string that you can set and will be store by Authorize.Net with this transaction so that you can reconcile the data with the information in your application.

Here is a more complex example of workflow where more variables are exposed:

  1. from gluon.contrib.AuthorizeNet import AIM
  2. payment = AIM(login='cnpdev4289',
  3. transkey='SR2P8g4jdEn7vFLQ',
  4. testmod=True)
  5. payment.setTransaction(creditcard, expiration, total, cvv, tax, invoice)
  6. payment.setParameter('x_duplicate_window', 180) # three minutes duplicate windows
  7. payment.setParameter('x_cust_id', '1324') # customer ID
  8. payment.setParameter('x_first_name', 'Agent')
  9. payment.setParameter('x_last_name', 'Smith')
  10. payment.setParameter('x_company', 'Test Company')
  11. payment.setParameter('x_address', '1234 Main Street')
  12. payment.setParameter('x_city', 'Townsville')
  13. payment.setParameter('x_state', 'NJ')
  14. payment.setParameter('x_zip', '12345')
  15. payment.setParameter('x_country', 'US')
  16. payment.setParameter('x_phone', '800-555-1234')
  17. payment.setParameter('x_description', 'Test Transaction')
  18. payment.setParameter('x_customer_ip', socket.gethostbyname(socket.gethostname()))
  19. payment.setParameter('x_email', 'you@example.com')
  20. payment.setParameter('x_email_customer', False)
  21. payment.process()
  22. if payment.isApproved():
  23. print 'Response Code: ', payment.response.ResponseCode
  24. print 'Response Text: ', payment.response.ResponseText
  25. print 'Response: ', payment.getResultResponseFull()
  26. print 'Transaction ID: ', payment.response.TransactionID
  27. print 'CVV Result: ', payment.response.CVVResponse
  28. print 'Approval Code: ', payment.response.AuthCode
  29. print 'AVS Result: ', payment.response.AVSResponse
  30. elif payment.isDeclined():
  31. print 'Your credit card was declined by your bank'
  32. elif payment.isError():
  33. print 'It did not work'
  34. print 'approved', payment.isApproved()
  35. print 'declined', payment.isDeclined()
  36. print 'error', payment.isError()

Notice the code above uses a dummy test account. You need to register with Authorize.Net (it is not a free service) and provide your own login, transkey, testmode=True or False to the AIM constructor.