Using Paypal with Django

by shabda on November 11, 2008

Paypal has a comprehensive API to use their services programatically. The ExpressCheckout API allows you to get the user’s details and then process the payments on your servers. They include a SOAP and NVP API. With NVP you do a GET to the Paypal servers with Url encoded values, get responses in plain text and work with them.

The basic flow for ExpressCheckout is something like this,

  1. You make a SetExpressCheckout request to Paypal, passing your credentials and and the amount you want to charge etc.
  2. Paypal returns an response with ACK of SUCCESS and token which you need to pass to subsequent requests.
  3. You transfer the user to Paypal site, passing the token returned in step 2.
  4. User logs in, and authorises transfer. Paypal redirects back to the SUCCESS_URL specified in step 1, passing the token and PayerID.
  5. You make a GetExpressCheckoutDetails request to Paypal, apssing token, payer id and other details.
  6. Paypal returns the user’s and transactions details.
  7. You ask user to confirm details.
  8. You make a DoExpressCheckoutPayment request to Paypal. At this point the money is transferred from user’s account to your account.

Now you can do the requests to Paypal very simply by sending requests, (it is just Url encoded name-value pair), but here is a Django snippet to make this wonderfully easy.

Before you can make requests to Paypal, servers you need to get API credentials. While developing your app, you of course, do not want to use actual Paypal money. Paypal makes available a sandbox where you can use virtual money before you go live.

  1. Go to developer.paypal.com and request a new sandbox API credentials.
  2. (Optionally)Read https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_api_reference to understand how does the Paypal NVP api works.
  3. We would two pages. [a] View 1: Where we do SetExpressCheckout and show a link to Paypal. [b] View 2: Where we do GetExpressCheckoutDetails, get the user’s details, get a confirm from user. On a confirmation from user we post to the same page and do a DoExpressCheckoutPayment.

[Totally untested code ahead. I am copying and simplifying from one of our applications.]

#view 1

def veiw1(request):
        ...........
    pp = paypal.PayPal()
    token = pp.SetExpressCheckout(...)
    paypal_url = pp.PAYPAL_URL + token
    payload = {'paypal_url':paypal_url}
    return render_to_response('template1.html', payload, RequestContext(request))

In the template send user to {{ paypal_url }} when they want to pay.

#View 2
#View 2 would be called after Paypal redirects after user authorises the transfer.

def view2(request):
    token = request.GET.get('token', '')
    pp = paypal.PayPal()
    if request.method == 'GET':
        paypal_details = pp.GetExpressCheckoutDetails(token, return_all = True)
        payload = {}
        if 'Success' in paypal_details['ACK']:
            payload['ack'] = True
            token = paypal_details['TOKEN'][0]
            first_name = paypal_details['FIRSTNAME'][0]
            .....
        return render_to_response('template2.html', payload, RequestContext(request))
    if request.method == POST:
        payment_details  = pp.DoExpressCheckoutPayment(token = token)
        if 'Success' in payment_details['ACK']:
            pass
            #We have been paid. DO things like, enable subsciprion, ship goods etc.
            return HttpResponseRedirect(payment_done_url)

Here in template2.html, we show the user/transaction details, and a on user’s confirmation do a post to the same url. This should help you get started with integrating Paypal with Django.

Resources.

  1. Paypal developer forums
  2. Paypal developer documentation

Need to build a Paypal enabled webapp? We can help

No related posts.

{ 2 trackbacks }

Willie Pritchetts WebBlog » Blog Archive » Using PayPal with Django
December 28, 2008 at 9:26 pm
Exploring Authorize.net Payment Gateway Options and integrating it with django — The Uswaretech Blog - Django Web Development
April 8, 2009 at 8:09 am

{ 15 comments… read them below or add one }

1 Yashh November 12, 2008 at 2:42 pm

Awesome. something I wanted to play with… cool!!

2 Josh November 12, 2008 at 2:54 pm

I’m a little confused about the order in which you’re doing things in your example. It seem to me that your view1 is like a checkout page where they see the details of the purchase and then have a link by which they can choose to pay with PayPal (and possibly other links to pay with other methods). The click that link, are taken to the PayPal site where they log in and confirm the transaction, then are taken back to your site at view2 where they confirm the transaction again? I guess I’m just not getting the flow here. Why isn’t their having logged into PayPal and confirmed there enough to actually process the payment as soon as they’re returned to your site?

3 Lakshman November 13, 2008 at 2:29 am

Josh: This is so you can do the checkout on your own site. You get the details of user who authorised the transaction, and then do the checkout on your site, not on paypal’s.

4 omtv November 13, 2008 at 10:07 pm

Quite a useful script, thanks a lot!

5 Peter November 13, 2008 at 11:21 pm

I don’t see the purpose of having the user confirm twice (the second time on your site). Why not just issue the DoExpressCheckoutPayment() after they have hit your “success” view? I mean without a valid token the transaction will not be processed anyways.

Seems like the extra step isn’t really needed.

I personally still use IPN for my payment processing app but I have been looking into this method lately. Simply because sometimes IPN has a delay in the confirmation and my customers end up waiting a minute or two before they can download their purchase. PITA.

6 ZooKeeper January 12, 2009 at 4:01 am

Thank you so much!

Is there going to be an updated version of this snippet?

7 SpongieFan May 26, 2009 at 5:15 pm

So where’s an example for a directpayment? Not everyone is using expresscheckout ya know… Thanks!

8 Dhruv July 18, 2009 at 7:16 pm

I didnt get this part

‘Go to developer.paypal.com and request a new sandbox API credentials. ‘

I went there , made account, created API credentials and under then under test accounts I see some information. What I dont know is how to use that information in the code. What information to be used and where in the code?

Help please.

Thanks, Dhruv

9 Adobe Business Catalyst October 24, 2009 at 4:14 am

Very useful for my ecommerce site im developing! Thank!

10 Arno Smi January 13, 2010 at 3:06 am

I keep getting a error 500 sent from paypals ipn any ideas why?

11 shabda January 13, 2010 at 6:41 am

@arno

What step?

12 seo January 13, 2010 at 9:12 pm

seo(搜索引擎優化)是我們主要業務,為大型企業網絡提供SEO搜尋引擎最佳化解決方案;數千家中大型企業網站營銷策劃經驗,提供企業SEO培訓,整站優化方案制定,整站優化實施,百度網站收錄恢復,網站重構壹條龍服務

13 dariush April 13, 2010 at 3:23 pm

thank you this helpful information.

I somehow get the following error message when during “request.method == ‘POST’”:

“The view ecomstore.checkout.views.process_paypal didn’t return an HttpResponse object.”

My view code: BEGIN def process_paypal(request, template_name=’checkout/order_confirm.html’): “”" Paypal API GetExpressCheckoutDetails “”" token = request.GET.get(‘token’, ”) transaction_id = request.GET.get(‘transaction_id’, ”) amount_with_ship_price = request.GET.get(‘amt’, ”) pp = paypal.PayPal() if request.method == ‘GET’: paypal_details = pp.GetExpressCheckoutDetails(token, return_all = True) payload = {} if ‘Success’ in paypal_details['ACK']: payload['ack'] = True if paypal_details['TOKEN'][0] == token: # Make sure TOKEN matches the value in SetExpressCheckout response token = paypal_details['TOKEN'][0] email_adress = paypal_details['EMAIL'][0] … else: error_message = u’TOKEN from GetExpressCheckoutDetails does not match the SetExpressCheckout response TOKEN’ form = CheckoutForm() page_title = ‘Order Confirm’ return render_to_response(template_name, locals(), context_instance=RequestContext(request)) if request.method == ‘POST’: payment_details = pp.DoExpressCheckoutPayment(token = token, payer_id = transaction_id, amt = amount_with_ship_price) if ‘Success’ in payment_details['ACK']: request.session['order_number'] = order_number receipt_url = urlresolvers.reverse(‘checkout_receipt’) return HttpResponseRedirect(receipt_url) END

I don’t know if there is anything wrong with the indentation.

Thank you for your help.

14 dariush April 13, 2010 at 3:27 pm

thank you this helpful information.

I somehow get the following error message when during “request.method == ‘POST’”:

“The view ecomstore.checkout.views.process_paypal didn’t return an HttpResponse object.”

My view code:

def process_paypal(request, template_name='checkout/order_confirm.html'):
    """ Paypal API GetExpressCheckoutDetails """
    token = request.GET.get('token', '')
    transaction_id = request.GET.get('transaction_id', '')
    amount_with_ship_price = request.GET.get('amt', '')
    pp = paypal.PayPal()
    if request.method == 'GET':
        paypal_details = pp.GetExpressCheckoutDetails(token, return_all = True)
        payload = {} 
        if 'Success' in paypal_details['ACK']:
            payload['ack'] = True
if paypal_details['TOKEN'][0] == token: # Make sure TOKEN matches the value in SetExpressCheckout response token = paypal_details['TOKEN'][0] email_adress = paypal_details['EMAIL'][0] ... else: error_message = u'TOKEN from GetExpressCheckoutDetails does not match the SetExpressCheckout response TOKEN'
form = CheckoutForm() page_title = 'Order Confirm' return render_to_response(template_name, locals(), context_instance=RequestContext(request)) if request.method == 'POST': payment_details = pp.DoExpressCheckoutPayment(token = token, payer_id = transaction_id, amt = amount_with_ship_price) if 'Success' in payment_details['ACK']: request.session['order_number'] = order_number receipt_url = urlresolvers.reverse('checkout_receipt') return HttpResponseRedirect(receipt_url)

I don’t know if there is anything wrong with the indentation.

Thank you for your help.

15 dariush April 13, 2010 at 3:32 pm

sorry I don’t know how to paste my sample code properly:

http://dpaste.com/183479/

Leave a Comment

Additional comments powered by BackType

Previous post:

Next post: