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.

About tommychheng
I write a tech blog at http://tommy.chheng.com

46 Responses to Paypal Adaptive Ruby Gem Released

  1. Matt says:

    Do you have an example of how your gem does Parallel payments?

  2. tommychheng says:

    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"}]},

  3. tommychheng says:

    testing if posted in right area

  4. guest2222222 says:

    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

  5. tommychheng says:

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

  6. ncri says:

    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

  7. ncri says:

    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.

  8. tommychheng says:

    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.

  9. ncri says:

    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.

  10. tommychheng says:

    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}]}

  11. ncri says:

    Thanks!

  12. Kevin says:

    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?

  13. tommychheng says:

    yes, sign up for an id at http://x.com

  14. JJ says:

    @Kevin you have to log in https://www.x.com/ and somewhere in profile you will find application_id. For production application_id you have to contact to paypal.

  15. Adam Eberlin says:

    looks great! good work!

  16. Paddy says:

    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

  17. tommychheng says:

    looks like a typo, it should be pay_response

  18. Paddy says:

    Also can you fix it in github too …http://github.com/tc/paypal_adaptive

  19. tommychheng says:

    yes, i'll do it right now, thanks for catching it

  20. bundacia says:

    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.

  21. tommychheng says:

    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

  22. bundacia says:

    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.

  23. Enabfluw says:

    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!

  24. tommychheng says:

    Hi, you can also use a Rails action as well. See https://github.com/tc/paypal_a… for an example.

  25. eladmeidar says:

    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?

  26. eladmeidar says:

    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?

    • Rob says:

      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!

  27. tommychheng says:

    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.

  28. eladmeidar says:

    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?

  29. eladmeidar says:

    nevermind that, i shouldn't be coding drunk :) thanks for an awesome gem.

  30. Chim Kan says:

    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?

  31. Chim Kan says:

    Ignore my last post. I didn’t uploaded the file. :)

  32. prasad says:

    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.

  33. prasad says:

    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’

  34. prasad says:

    Hi , Tommychheng

    Please reply to me……

    PRASAD

  35. Dmitry Polushkin says:

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

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

  36. ciriusmex says:

    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.

  37. 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.

  38. rishi says:

    any chanbe this gem would work with activemerchant? or any other suggestions for same?

  39. prasad says:

    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

  40. zksherm says:

    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

  41. Valerio says:

    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

Leave a Reply

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

Gravatar
WordPress.com Logo

Please log in to WordPress.com to post a comment to your blog.

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

Follow

Get every new post delivered to your Inbox.