In my last post I covered integrating a rails application with Espago payments. Yes, I know, it’s not a very popular payment provider so I wanted to write about something more known and international. Lately we’ve been looking for a payment service for one of our first startup projects petpetum. We’ve made some research and we decided to choose Braintree. I will not write about fees and stuff because it’s not the point. I just want to present how easy it is to integrate with braintree (no, they haven’t paid me to say that ;) ).

Standard setup

What can you do with Braintree? Basically all types of credit card transactions and paypal transactions. As always I created sample application that you can find on my github. So everything that I write about you can find there.

Every integration should be started by visiting the provider’s page and creating a sandbox account. After that we are almost ready to go. You need to obtain sandbox API keys like Merchant ID, Public Key etc.

Next we need to add the braintree javascript.

%script{:src => "https://js.braintreegateway.com/v2/braintree.js"}

Why do we need this line of code? Because that’s how braintree works. When a user types in his credit card credentials, the parameters are submitted straight to the braintree gateway thanks to this script. We get a response callback, but I will write more about it later. Let’s continue our setup with adding the braintree gem to our Gemfile.

gem 'braintree'

Now we just need to configure the API credentials for our app.

Braintree::Configuration.environment = :sandbox
Braintree::Configuration.merchant_id = "merchant_id"
Braintree::Configuration.public_key = "public_key"
Braintree::Configuration.private_key = "private_key"

Charging a customer

There are many many things happeninng while creating a new payment. Fortunately those “many many things” are mainly on the braintree gateway side. I won’t describe the whole process, but if you want to read about it you can find it here at braintree documentatin. For now, we need to focus on creating a new client and charging him (the latter being the bast part). There are two ways of doing this. You can use the so called “drop-in payment ui” or you can create the form by yourself. The first one is an out of box component provided by braintree payments and looks like this:

But let’s say we want to create our custom form. To do that we need to provide the form with special braintree fields.

%h1 Braintree transaction
=form_tag '/charge_client', role: 'form' do
  .form-group
    = label_tag 'Cardholder name'
    = text_field_tag 'Cardholder name', nil, name: nil, placeholder: 'Cardholder name', data: {'braintree-name' => 'cardholder_name'}, class: 'form-control'
  .form-group
    = label_tag 'Card number'
    = text_field_tag 'Card number', nil, name: nil, placeholder: 'Card number', data: {'braintree-name' => 'number'}, class: 'form-control'
  .form-group
    = label_tag 'Cvv number'
    = text_field_tag 'Cvv number', nil, name: nil, placeholder: 'CVV', data: {'braintree-name' => 'cvv'}, class: 'form-control'
  .form-group
    = label_tag 'Month'
    = text_field_tag 'Month', nil, name: nil, placeholder: 'Month in MM format', data: {'braintree-name' => 'expiration_month'}, class: 'form-control'
    = label_tag 'Year'
    = text_field_tag 'Year', nil, name: nil, placeholder: 'Year in YY format', data: {'braintree-name' => 'expiration_year'}, class: 'form-control'
  .form-group
    =submit_tag 'Charge', class: 'btn btn-default'

Notice the ‘name: nil’. It is important that we never pass the parameters to our server.

Ok so we have a form calling the action ‘charge_client’, but as we know we cannot process params from customer ourselves so we need to use the braintree script. There are two steps to doing this. First is creating a client token on the server. As it is said at Braintree documentation, a token is a signed data blob that contains both configuration and authorization.

@client_token = Braintree::ClientToken.generate

Token is needed in the second step where we assign braintree js to our form.

braintree.setup("your-generated-client-token", "custom", {id: "your-id-of-the-form"});

Ok so in our ‘charge_client’ action let’s just see what parameters are being sent.

{"utf8"=>"✓", "authenticity_token"=>"A5n5NPU9hNgep1TrFTNlXSBsVJclWXEZMr7QjxDjFpI=", "payment_method_nonce"=>"f7641bc1-cd28-489a-bf4e-9abb33d9632a", "action"=>"charge_client", "controller"=>"payments"}

Voila, we have a magic payment_method_nonce parameter. That means braintree collected all the fields in our form, processed it and sent us a pretty long string which is needed to create our first transaction. Now it’s time for some real cool funcionality. Let’s fill in our ‘charge_client’ action with some content.

def charge_client
    result = Braintree::Transaction.sale(
      :amount => "100.00",
      :payment_method_nonce => params[:payment_method_nonce]
    )
    puts result
    puts result.success?
    puts result.transaction.status
  end

And see what it says.

I, [2014-08-28T10:07:01.063450 #67970]  INFO -- : [Braintree] [28/Aug/2014 08:07:01 UTC] POST /transactions 201
#<Braintree::SuccessfulResult:0x007fecb8123e08>
true
authorized

Notice that the result is an object. This is pretty great because for example in Espago payments we were getting a hash. Getting an object is more ‘Ruby way’ and for me is more readable. You can find all objects defined at braintree refference.

But let’s get back to our stuff. As we can see our transaction succedeed and we have info that we have been authorized. Wasn’t hard, was it ?

Next we would like to add some error handling and we are ready to go. Basically we need to check if the result was successful.

if result.success?
  flash[:notice] = "Transaction successful"
  redirect_to root_url
else
  flash[:danger] = "Transaction error: #{result.transaction.processor_response_text}"
  redirect_to root_url
end

This should do the trick. Notice that you can get precise info about errors. To perform error transaction read the testing section. There are combinations of amounts, credit card number and cvvs that results in error transaction. But easiest way to test a failed transaction is by passing two identical credit cards one by one.

Creating customer

Depending on your application you may like to create a customer first. It is possible of course. A method in the User model could look like this:

def init_braintree(payment_nonce)
  result = Braintree::Customer.create(
    :credit_card => {
      :payment_method_nonce => payment_nonce,
      :options => {
        :verify_card => true
      }
    }
  )
  if result.success?
    self.customer_id = result.customer.id
    self.save
    true
  else
    self.destroy
    false
  end
end

When we receive customer id from braintree we can save it and use it for charging the user in the future. It can be easily done by passing ‘customer_id’ to the transaction hash.

result = Braintree::Transaction.sale(
  :customer_id => customer_id,
  :amount => amount
)

Is that all?

No it’s not. I just covered the basics of customer charging/creation. However there are some things that can be mentioned:

  1. Braintree doesn’t validate and verify the cardholder’s name.
  2. Braintree can verify the credit card number and the expiration date, however on the sandbox account expiration date is not validated either. Those two things I couldn’t find in documentation so I’m sharing with you (I got this info from the braintree support).

I hope that when you read my post, rails-braintree integration will be simple and quick.

Post tags:

Work
with us

Tell us about your idea
and we will find a way
to make it happen.

Get estimate

Join our awesome team
Check offers