Paypal Adaptive Ruby Gem Released

I have been tinkering with the new Paypal Adaptive Payments API and created a simple ruby gem to interface with it. Still pretty new but I’m using it with little problems so far. Submit bug reports if found. See the code at github

Paypal Adaptive Payments API
The adaptive payments api gives you the opportunity to make preapproved payments, chained payments and parallel payments. The chained/parallel payments are great for commission-based apps or if you are trying to connect a buyer to multiple sellers with a single interface.

How to use with Rails:
Install:

sudo gem install paypal_adaptive

Setup your API info by adding a paypal_adaptive.yml to your config folder:


development:
  environment: "sandbox"
  username: "sandbox_username"
  password: "sandbox_password"
  signature: "sandbox_signature"
  application_id: "sandbox_app_id"

test:
  environment: "sandbox"
  username: "sandbox_username"
  password: "sandbox_password"
  signature: "sandbox_signature"
  application_id: "sandbox_app_id"

production:
  environment: "production"
  username: "my_production_username"
  password: "my_production_password"
  signature: "my_production_signature"
  application_id: "my_production_app_id"

Make the payment request:


pay_request = PaypalAdaptive::Request.new

data = {
"returnUrl" => "http://testserver.com/payments/completed_payment_request",
"requestEnvelope" => {"errorLanguage" => "en_US"},
"currencyCode"=>"USD",
"receiverList"=>{"receiver"=>
     [{"email"=>"testpp_1261697850_per@nextsprocket.com", "amount"=>"10.00"}]},
"cancelUrl"=>"http://testserver.com/payments/canceled_payment_request",
"actionType"=>"PAY",
"ipnNotificationUrl"=>"http://testserver.com/payments/ipn_notification"
}

pay_response = pay_request.pay(data)

if pay_response.success?
  redirect_to pay_response.approve_paypal_payment_url
else
  puts pay_response.errors.first['message']
  redirect_to failed_payment_url
end

Once the user goes to pay_response.approve_paypal_payment_url, they will be prompted to login to Paypal for payment.

Upon payment completion page, they will be redirected to http://testserver.com/payments/completed_payment_request.

They can also click cancel to go to http://testserver.com/payments/canceled_payment_request

The actual payment details will be sent to your server via “ipnNotificationUrl” You have to create a listener to receive POST messages from paypal. I added a Rails metal template in the templates folder which handles the callback.

Additionally, you can make calls to Paypal Adaptive’s other APIs:


payment_details, preapproval, preapproval_details,
cancel_preapproval, convert_currency, refund

Input is just a Hash just like the pay method. Refer to the Paypal Adaptive manual for more details.

61 thoughts on “Paypal Adaptive Ruby Gem Released

  1. tommychheng

    Hey Matt,Just add two or more people to the receiverList to make it a parallel payment like:”receiverList”=>{“receiver”=> [{"email"=>"person1@chheng.com", "amount"=>"10.00"}, {"email"=>"person2@chheng.com", "amount"=>"20.00"}]},

    Reply
  2. guest2222222

    Hi Tommy,Above format is not working for me, getting an error message “This kind of unilateral payment is not allowed”. I had provided API username, pass, signature. Do I missing something?Thanks

    Reply
  3. tommychheng

    hey, if you are getting a 'unilateral payment is not allowed', make sure the test email is a registered email in your sandbox account.

    Reply
  4. ncri

    Hi. Looks good! Thx. Just trying it out.What do I need to put in application_id: “sandbox_app_id”?I didn't get one with my sandbox account and even googling doesn't reveal the answer…Nico

    Reply
  5. ncri

    Works fine now. But I'd require users to also be able to pay with credit card, without having a PP account, like it is possible with website payments standard checkout. Also I don't like the user to see how much money goes to which email address.So ideally I'd like PP Website Payments Standard checkout capability but diverting the payment to different paypal accounts in the background. I think this must be somehow possible.Any ideas are greatly appreciated.

    Reply
  6. tommychheng

    hi nico, you are right that paypal adaptive payments don't support credit card payments yet. It is scheduled in their roadmap. You can get a date from paypal to see how soon this is.

    Reply
  7. ncri

    Thanks for the info. Any references?Is your gem also supporting chained payments? That is more interesting for me, as I don't like payers to see all the receivers of the payment.

    Reply
  8. tommychheng

    There were a few posts on the http://x.com regarding CC payments coming in the near future.To do chained payments, just add a primary boolean flag:{“receiver”=> [{"email"=>"PRIMARY", "amount"=>"100.00", "primary" => true}, {"email"=>"OTHER", "amount"=>"75.00", "primary" => false}]}

    Reply
  9. Kevin

    Hey Tommy… newbie question but I see the username/password/signature fields on my developer paypal screen but where do I find the application_id? Is that just an arbitrary name that I can pick or is it somewhere on developer.paypal.com?

    Reply
  10. Paddy

    I am getting this error and used as the above example as stated above:undefined local variable or method `pp_response'please advice!Thank you for your time

    Reply
  11. bundacia

    This looks great. I am having one problem getting it to work though… I'm getting this error:/home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:677:in `connect': SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (OpenSSL::SSL::SSLError) from /home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:677:in `connect' from /home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:637:in `do_start' from /home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:626:in `start' from /home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:1160:in `request' from /home/user/.rvm/rubies/ruby-1.9.2-head/lib/ruby/1.9.1/net/http.rb:970:in `post' from /home/user/.rvm/gems/ruby-1.9.2-head/gems/paypal_adaptive-0.1.0/lib/request.rb:79:in `call_api' from /home/user/.rvm/gems/ruby-1.9.2-head/gems/paypal_adaptive-0.1.0/lib/request.rb:31:in `pay' from ./test.rb:18:in `<main>'When rolling this stuff by hand without your gem the solution was to add this line:http.verify_mode = OpenSSL::SSL::VERIFY_NONEWhere http is the Net::HTTP object. Is there a way to do the same thing using your gem, or is this something I've got misconfigured?Thanks.

    Reply
  12. tommychheng

    This looks like a net::http error?If you are using Rails, you can try sticking http.verify_mode = OpenSSL::SSL::VERIFY_NONE into ssl.rb of config/initializers

    Reply
  13. bundacia

    Thanks for the reply. Actually, it looks like I can fix this by reopening the Net::HTTP class and tweaking the initialize method to it sets a ca_path for all new objects so it can find the right certificates. Here's what I did:class Net::HTTP alias :o rig_initialize :initialize def initialize(*args) # Call the original init orig_initialize(*args) # Setup ssl cert path @ca_path = '/etc/ssl/certs' endend/etc/ssl/certs is where the certs live on Ubuntu. Don't know how common that is across platforms.

    Reply
  14. Enabfluw

    Nice little gem! I'm having trouble figuring out how to use the IPN. I'm not sure how to use the metal template. I should make an action to handle it, right? I made an “ipn” method in one of my controllers and set that to the ipnNotificationUrl, but after that, I haven't the foggiest idea what to do next. I'd appreciate any help!

    Reply
  15. eladmeidar

    Hi There,i tried your example as it is, but when i use your metal template the “ipn.verified?” call always returns false (send_back sets it according your source). anything special i should be paying attention to?

    Reply
  16. eladmeidar

    Hi There,i tried your example as it is, but when i use your metal template the “ipn.verified?” call always returns false (send_back sets it according your source). anything special i should be paying attention to?

    Reply
    1. Rob

      I think it’s great that you’re tniakg the time to explain the answers! I really like this series of articles! Keep up the great work!

      Reply
  17. tommychheng

    when you are doing the send back: ipn.send_back(env['rack.request.form_vars'])check the env['rack.request.form_vars'] value before you send it outMake sure that's not garage.

    Reply
  18. eladmeidar

    turns out the problem was an authentication filter was blocking the post-back from Paypal.Now i am banging my head with trying to understand the incoming parameters.when i create the inital payment request, i keep a record with the payKey (something i need to find back and activate when the payment callback is processes) but it seems that the incoming parameters (rack.env) don't contain any reference to the initial request (payKey is different).ideas on how am i supposed to link between the incoming IPN to my pre-existing payment record?

    Reply
  19. Chim Kan

    In my development environment the Paypal sandbox is working but it’s not working on production mode.

    I’ve changed the paypal_adaptive.yml to ‘sandbox’ in the production, but still it doesn’t work. Is there anything else that I should change to see the production using sandbox?

    Reply
  20. prasad

    Hi ,

    I am using papal_adaptive gem. I provided my paypal sandbox account details in papal_adaptive.yml file. When I call pay_request = PaypalAdaptive::Request.new, it throws the error below:

    You have a nil object when you didn’t expect it!
    You might have expected an instance of ActiveRecord::Base.
    The error occurred while evaluating nil.[]

    I am using ruby 1.9.2 and rails 3.0.7 in windows system.

    Reply
  21. prasad

    Hi , tommychheng

    My application error is :
    ———————————
    You have a nil object when you didn’t expect it!
    You might have expected an instance of ActiveRecord::Base.
    The error occurred while evaluating nil.[]

    paypal_adaptive (0.2.1) lib/config.rb:34:in `load’
    paypal_adaptive (0.2.1) lib/config.rb:26:in `initialize’
    paypal_adaptive (0.2.1) lib/request.rb:14:in `new’
    paypal_adaptive (0.2.1) lib/request.rb:14:in `initialize’
    app/controllers/ven_controller.rb:8:in `new’
    app/controllers/ven_controller.rb:8:in `index’
    actionpack (3.0.7) lib/action_controller/metal/implicit_render.rb:5:in `send_action’
    actionpack (3.0.7) lib/abstract_controller/base.rb:150:in `process_action’
    actionpack (3.0.7) lib/action_controller/metal/rendering.rb:11:in `process_action’
    actionpack (3.0.7) lib/abstract_controller/callbacks.rb:18:in `block in process_action’
    activesupport (3.0.7) lib/active_support/callbacks.rb:436:in `_run__954984038__process_action__457429307__callbacks’
    activesupport (3.0.7) lib/active_support/callbacks.rb:410:in `_run_process_action_callbacks’
    activesupport (3.0.7) lib/active_support/callbacks.rb:94:in `run_callbacks’
    actionpack (3.0.7) lib/abstract_controller/callbacks.rb:17:in `process_action’
    actionpack (3.0.7) lib/action_controller/metal/instrumentation.rb:30:in `block in process_action’
    activesupport (3.0.7) lib/active_support/notifications.rb:52:in `block in instrument’
    activesupport (3.0.7) lib/active_support/notifications/instrumenter.rb:21:in `instrument’
    activesupport (3.0.7) lib/active_support/notifications.rb:52:in `instrument’
    actionpack (3.0.7) lib/action_controller/metal/instrumentation.rb:29:in `process_action’
    actionpack (3.0.7) lib/action_controller/metal/rescue.rb:17:in `process_action’
    actionpack (3.0.7) lib/abstract_controller/base.rb:119:in `process’
    actionpack (3.0.7) lib/abstract_controller/rendering.rb:41:in `process’
    actionpack (3.0.7) lib/action_controller/metal.rb:138:in `dispatch’
    actionpack (3.0.7) lib/action_controller/metal/rack_delegation.rb:14:in `dispatch’
    actionpack (3.0.7) lib/action_controller/metal.rb:178:in `block in action’
    actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:62:in `call’
    actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:62:in `dispatch’
    actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:27:in `call’
    rack-mount (0.6.14) lib/rack/mount/route_set.rb:148:in `block in call’
    rack-mount (0.6.14) lib/rack/mount/code_generation.rb:93:in `block in recognize’
    rack-mount (0.6.14) lib/rack/mount/code_generation.rb:68:in `optimized_each’
    rack-mount (0.6.14) lib/rack/mount/code_generation.rb:92:in `recognize’
    rack-mount (0.6.14) lib/rack/mount/route_set.rb:139:in `call’
    actionpack (3.0.7) lib/action_dispatch/routing/route_set.rb:493:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/best_standards_support.rb:17:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/head.rb:14:in `call’
    rack (1.2.3) lib/rack/methodoverride.rb:24:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/params_parser.rb:21:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/flash.rb:182:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/session/abstract_store.rb:149:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/cookies.rb:302:in `call’
    activerecord (3.0.7) lib/active_record/query_cache.rb:32:in `block in call’
    activerecord (3.0.7) lib/active_record/connection_adapters/abstract/query_cache.rb:28:in `cache’
    activerecord (3.0.7) lib/active_record/query_cache.rb:12:in `cache’
    activerecord (3.0.7) lib/active_record/query_cache.rb:31:in `call’
    activerecord (3.0.7) lib/active_record/connection_adapters/abstract/connection_pool.rb:354:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:46:in `block in call’
    activesupport (3.0.7) lib/active_support/callbacks.rb:416:in `_run_call_callbacks’
    actionpack (3.0.7) lib/action_dispatch/middleware/callbacks.rb:44:in `call’
    rack (1.2.3) lib/rack/sendfile.rb:107:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/remote_ip.rb:48:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/show_exceptions.rb:47:in `call’
    railties (3.0.7) lib/rails/rack/logger.rb:13:in `call’
    rack (1.2.3) lib/rack/runtime.rb:17:in `call’
    activesupport (3.0.7) lib/active_support/cache/strategy/local_cache.rb:72:in `call’
    rack (1.2.3) lib/rack/lock.rb:11:in `block in call’
    :10:in `synchronize’
    rack (1.2.3) lib/rack/lock.rb:11:in `call’
    actionpack (3.0.7) lib/action_dispatch/middleware/static.rb:30:in `call’
    railties (3.0.7) lib/rails/application.rb:168:in `call’
    railties (3.0.7) lib/rails/application.rb:77:in `method_missing’
    railties (3.0.7) lib/rails/rack/log_tailer.rb:14:in `call’
    rack (1.2.3) lib/rack/content_length.rb:13:in `call’
    rack (1.2.3) lib/rack/handler/webrick.rb:52:in `service’
    /home/mahesh/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/httpserver.rb:111:in `service’
    /home/mahesh/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/httpserver.rb:70:in `run’
    /home/mahesh/.rvm/rubies/ruby-1.9.2-p0/lib/ruby/1.9.1/webrick/server.rb:183:in `block in start_thread’

    Reply
  22. Dmitry Polushkin

    Prasad it’s easy, just add paypal_adaptive.yml to your config path.

    In the future, try to read code before to post stacktraces.

    Reply
  23. ciriusmex

    Hello, newbie question here. I’m trying to create a payment preapproval test but don’t know where to get this information:
    username: “sandbox_username”
    password: “sandbox_password”
    signature: “sandbox_signature”
    application_id: “sandbox_app_id”

    From my x.com account? From the enterprise sandbox account I created for the preapproval?

    Thanks for the help.

    Reply
    1. hhk

      @ciriusmex
      you got solution ? I also wanna test payment preapproval .. but i don’t know how to start work. could you please share with me example code if u got it?

      Reply
  24. Juan Capristán

    Hi there,
    I’ve been trying to make this gem work with no luck: I always get the error “undefined method ‘strip’ for nil:NilClass”. The last lines of my framework trace are the next ones:

    activesupport (3.0.3) lib/active_support/whiny_nil.rb:48:in `method_missing’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:1296:in `block in initialize_http_header’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:1294:in `each’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:1294:in `initialize_http_header’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:1662:in `initialize’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:1779:in `initialize’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:970:in `new’
    C:/Ruby192/lib/ruby/1.9.1/net/http.rb:970:in `post’
    paypal_adaptive (0.2.2) lib/request.rb:91:in `call_api’
    paypal_adaptive (0.2.2) lib/request.rb:33:in `pay’

    I think this could be due to my ruby or rails version. I’m working under rails 3.0.3 and ruby 1.9.2. Another possible problem is that I commented “application_id” field in paypal_adaptive.yml config file because I couldn’t find this info anywhere inside x.com (i created an account) neither paypal.com (inside my business acount nor my sandbox account). I also tested this field uncommented but with a blank value without any luck.

    Any help would be really apreciated.

    Reply
  25. prasad

    Hi ,
    I have seen refund method , For a shopping cart application refund method functionality required , but In paypal adaptive payments pdf refund option requires third party access . Shall I know how to check sellers account third party access option , it means for a refund option , sellers have to give third party access to my api , so I need to check every time , is seller given third party access or not . How it is possible .

    Thank in Advance,
    PRASAD

    Reply
  26. zksherm

    Hey Tommy,

    Thanks for the great gem, it saved me a lot of time. I was just curious if it’s possible to use the delayed chained payment features that paypal offers with this gem. If so do you think you could give me some tips? Specifically I want to instantly transfer the money to the primary user and at a later specified date, transfer part of the money from the primary receiver to the secondary receiver.

    Thanks,

    Zach

    Reply
  27. Valerio

    Hi Tommy,
    Great gem! Thank you.
    Could you please provide an example of ssl certificate usage?
    Which file path should I put in the ssl_cert_file: ?
    My certificate or paypal certificate?
    And my private key?
    And more generally, since all the payment interactions will be in the paypal website, is it less secure not to use ssl? What would be the differences?

    Thank you very much
    Valerio

    Reply
  28. Luis

    Hi tommychheng,

    Do you know how long take to achieve the api key to use the adaptive payments out of sandbox?

    Thanks

    Reply
  29. hhk

    Hi Tommy,

    Could you please take look the error?
    I got error while I call pay method as follow:

    returnUrl = “http://localhost:3000/payment/payment_success/”+params[:id]
    cancelUrl = “http://localhost:3000/payment/payment_cancel”

    ##### Payment after preapproved
    pay_request = PaypalAdaptive::Request.new
    data = {
    “returnUrl” => returnUrl,
    “requestEnvelope” => {“errorLanguage” => “en_US”},
    “currencyCode”=>”SGD”,
    “receiverList”=>{“receiver”=>
    [{"email"=>"htay_1319791352_biz@gajah.com.sg", "amount"=>"1.00"}]},
    “cancelUrl”=> cancelUrl,
    “actionType”=>”PAY”,
    “preapprovalKey” => @user.preapprovalKey #”PA-5WN75327B39732150″
    }

    pay_response = pay_request.pay(data)
    if pay_response.success?
    session[:pay_response] = pay_response['payKey']
    redirect_to pay_response.approve_paypal_payment_url
    else
    puts pay_response.errors.first['message']
    #redirect_to failed_payment_url
    respond_to do |format|
    format.html { redirect_to inventories_url, :notice => pay_response.errors.first['message'] }
    end

    Error :
    This transaction has already been approved. Please visit your PayPal Account Overview to see the details.
    However, payment is successul but not redirect back to specified “returnUrl”.
    Could you pelase advice?

    Thank

    Reply
  30. arun

    Hi Tommy
    I’d require users to also be able to pay with credit card, without having a Paypal account, like it is possible with website payments standard.

    Reply
  31. Zack

    Hi, Tommy.

    We have a pretty simple requirement.

    We want to allow our users to request money from us, and for us to send them money via PayPal automatically (no manual login required from either the requester or from us).

    So the user would enter the following:
    * PayPal email address to receive the money
    * Amount (amount and currency)

    Is this something Adaptive Payment can support?

    Looking at your example above, we won’t need returnUrl or cancelUrl.
    As the sender of money is us (the website, the merchant), and it should be completely
    automated. No one is going to manually enter a password to PayPal to indicate that
    we own the merchant account. Is this possible?

    Thanks alot!
    Zack

    Reply
    1. tommychheng Post author

      Hi,
      I’m sorry but I’m not sure how to implement this reverse payment system. Maybe ask on the paypal forums? And you do have an answer which uses the paypal adaptive gem, please share it here as well. :)

      Reply
  32. Suprt

    Just wondering if it’s possible to include the line item details? i.e. product name, product description, price etc?

    Reply
  33. 田中和夫

    Thank for your work and this is great gem.
    I am working on developing web mobile app with JQuery Mobile. Is it possible to request Paypal login for mobile to Paypal through this gem?
    Thank in advance

    Reply
      1. 田中和夫

        I appreciate your quick reply. But I mean it works fine with the gem but it redirects to Paypal login page for Web. Is it possible for me to configure in order to redirect to Paypal log page for Mobile?

      2. tommychheng Post author

        I’m sorry, but i’m not sure if there is a paypal mobile login screen. Maybe try asking on the paypal adaptive forums. If you find an answer, feel free to share it here too :)

  34. Juan Pablo Montoya B.

    Hey tommy; I’ve just read lots of documentation, and your gem looks really great. I’ve been wondering how to receive payments before making the parallel payment to the recievers. I am developing an ecommerce site, where you can buy and sell things, so I need also receive payments. Does this gem supprt this? or do I have to use Active Merchant and PayPal Adaptive gems?

    Thanks for your response

    Reply
    1. tommychheng Post author

      Yes, this gem supports what you suggested. Maybe you want to do a chained payment system?

      A “chained payment” is the Paypal term to describe a process where a buyer makes a purchase from a single seller who then disperses payment to one or more sellers. This is a classic middle man scenario, where one vendor is offering products from a number of sources

      https://www.x.com/devzone/articles/creating-online-store-chained-payments-apis

      Reply
      1. Juan Pablo Montoya B.

        Yes, kind of; but I need to control those payments from the rails app. My payment logical is this one:

        User pays for an item,
        Site owner receives 30% of the payment,
        Item owner receives 70% of the payment.

        How do I send the transaction when the first user pays the total in the site?

        Thanks

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s