SquareEvent is built on the ActiveSupport::Notifications API. Incoming webhook requests are authenticated with the webhook signature. Define subscribers to handle specific event types. Subscribers can be a block or an object that responds to #call.
The gem is based on the excellent Stripe Event work from Integrallis Software, it has been adapted and re-written to work with Square webhooks.
# Gemfile
gem 'square_event'# config/routes.rb
mount SquareEvent::Engine, at: '/my-chosen-path' # provide a custom path# config/initializers/square_event.rb
SquareEvent.signing_secret = Rails.application.credentials.square[Rails.env][:webhook_secret]
SquareEvent.notification_url = Rails.application.credentials.square[Rails.env][:webhook_url]
SquareEvent.configure do |events|
events.subscribe 'payment.created' do |event|
# Define subscriber behavior based on the event object
event.class #=> SquareEvent::Event
event.type #=> "payment.created"
event.data #=> data": { "type": "payment", "id": "KkAkhdMs...
end
events.all do |event|
# Handle all event types - logging, etc.
end
endclass CustomerCreated
def call(event)
# Event handling
end
end
class BillingEventLogger
def initialize(logger)
@logger = logger
end
def call(event)
@logger.info "BILLING:#{event.type}:#{event.id}"
end
endSquareEvent.configure do |events|
events.all BillingEventLogger.new(Rails.logger)
events.subscribe 'customer.created', CustomerCreated.new
endSquareEvent.subscribe 'customer.' do |event|
# Will be triggered for any customer.* events
endSquare will cryptographically sign webhook payloads with a signature that is included in a special header sent with the request. Verifying this signature lets your application properly authenticate the request originated from Square. SquareEvent mandates that this is used for every request. Please set the signing_secret and notification_url configuration values:
SquareEvent.signing_secret = Rails.application.credentials.square[Rails.env][:webhook_secret]
SquareEvent.notification_url = Rails.application.credentials.square[Rails.env][:notification_url]Please refer to Square's documentation for more details: https://developer.squareup.com/docs/webhooks-api/validate-notifications
If you'd like to ignore particular webhook events (perhaps to ignore test webhooks in production, you can do so by returning nil in your custom event_filter. For example:
SquareEvent.event_filter = lambda do |event|
return nil if Rails.env.production? && !event.sandbox?
event
endSquareEvent can be used outside of Rails applications as well. Here is a basic Sinatra implementation:
require 'json'
require 'sinatra'
require 'square_event'
SquareEvent.signing_secret = ENV['SQUARE_SIGNING_SECRET']
SquareEvent.notification_url = ENV['SQUARE_NOTIFICATION_URL']
SquareEvent.subscribe 'payment.created' do |event|
# Look ma, no Rails!
end
post '/_billing_events' do
data = JSON.parse(request.body.read, symbolize_names: true)
SquareEvent.instrument(data)
200
endHandling webhooks is a critical piece of modern billing systems. Verifying the behavior of SquareEvent subscribers can be done fairly easily by stubbing out the HTTP signature header used to authenticate the webhook request. Tools like Webmock and VCR work well. RequestBin is great for collecting the payloads. For exploratory phases of development, UltraHook and other tools can forward webhook requests directly to localhost.
The Square ruby library does not currently offer an Event object to use to create or refer to webhook with, so their testing in Ruby is harder than with Stripe.
Special thanks to all the contributors.
Semantic Versioning 2.0 as defined at http://semver.org.
MIT License. Copyright 2020-2021 Andy Callaghan, Square work. Copyright 2012-2015 Integrallis Software original Stripe work.