Handling stripe webhooks with Ruby on Rails
Tags: rails, ruby, stripe, webhook
Published: 2019-03-26 18:24:05


---
title: Handling stripe webhooks with Ruby on Rails
published: true 
description: Handling stripe webhooks with Ruby on Rails
tags: rails, ruby, stripe, webhook
---

When accepting payments on a Ruby on Rails app, if you want to be aware of every actions that happen on stripe, you will have to implement the stripe [webhooks](https://stripe.com/docs/webhooks).

I found a nice way to handle them, which I'm going to share in this article.

I *strongly* discourage you to implement them on your own by adding a simple POST route to /webhooks, because:

- You need to check stripe's signature before accepting them (someone may be trying to impersonate Stripe!)
- There are gems available to simplify this task

In this tutorial, we're going to use a gem called [stripe_event](https://github.com/integrallis/stripe_event)

## Let's get started

### Installing the dependencies

The first step is to add the gem in your Gemfile. If you're new to ruby, the file is located at the root of your app.
 
```ruby
gem 'stripe_event'
```

Then, in your routes.rb file, located in /config, add the following line:

```ruby
mount StripeEvent::Engine, at: '/stripe-webhooks' #you can change this url
```

This will create a POST route to handle all the webhooks. We're going to implement that in a few moments, after we setup everything in the stripe dashboard 


### Setting up the webhooks

First, if you want to try the webhooks on your development environment, you will need to use a tool like [ngrok](https://ngrok.io).

Then, in your Stripe dashboard, navigate to Developers -> Webhooks or click on this [link](https://dashboard.stripe.com/account/webhooks).

Finally, switch to "test data" and add a new endpoint. In "URL to be called", add your ngrok URL followed by the route name you chose earlier.

Once you created your webhook, please note the signing secret for that webhook somewhwere.
![Signing secret](https://thepracticaldev.s3.amazonaws.com/i/45jfebj2hw7fubtzn8ms.png)


### Adding the credentials

We will now add the stripe credentials to the (relatively) new [rails encrypted credentials](https://www.engineyard.com/blog/rails-encrypted-credentials-on-rails-5.2)

To edit the credentials, type the following command:

```
EDITOR=nano rails credentials:edit
```

and write the following lines:

```yaml
stripe:
  development:
    publishable_key: 'pk_test_'
    secret_key: 'sk_test_'
    signing_secret: 'whsec_'
  production:
    publishable_key: 'pk_live_'
    secret_key: 'sk_live_'
    signing_secret: 'whsec_'
```

publishable_key and secret_key are your stripe keys, you can find them in your account settings, signing_secret is the secret we generated earlier.


### Configuring stripe_events

Create a file called "stripe_events.rb" in config/initializers and paste the following code

```ruby
Stripe.api_key = Rails.application.credentials.stripe[Rails.env.to_sym][:publishable_key]
StripeEvent.signing_secret = Rails.application.credentials.stripe[Rails.env.to_sym][:signing_secret]

StripeEvent.configure do |events|
  events.subscribe 'invoice.', Stripe::InvoiceEventHandler.new
end
```

The first two lines are setting the correct tokens, depending on your current environment (development or production)

In the last three lines, we are telling stripe_event to subscribe to all the events starting with 'invoice.' and redirect them to a class called "InvoiceEventHandler"

The next step is to implement this class.

In your app folder, create a new folder called "services" and add a folder called "stripe" in it.

Then, add a file called invoice_event_handler.rb in the stripe folder we just created.

```ruby
module Stripe
  class InvoiceEventHandler
    def call(event)
      begin
        method = "handle_" + event.type.tr('.', '_')
        self.send method, event
      rescue JSON::ParserError => e
        # handle the json parsing error here
        raise # re-raise the exception to return a 500 error to stripe
      rescue NoMethodError => e
        #code to run when handling an unknown event
      end
    end

    def handle_invoice_payment_failed(event)
    end

    def handle_invoice_payment_succeeded(event)
    end
  end
end
```

Here, I implemented two events: invoice.payment.failed and invoice.payment.succeeded. Using 'send', I'm forwarding the event to the correct method. (Credit: [@aradilopez](https://dev.to/arandilopez/efficent-webhook-handlig-with-ruby-on-rails-4pj))

That's it! 

In my various projects, I'm redirecting all the useful notifications to a slack channel, so I'm always aware of what's happening.