Webhooks

We recommend that you make use of a webhook to be notified of payment completion due to the real-time nature of the system. During your account set up we can configure a URL to which we will POST payment objects as we determine their status. We will only notify you of completed and errored payments through the webhook.

Note that webhooks should be treated as an unauthenticated event stream. If payment spoofing is a concern and you require higher levels of certainty about a payment, make an authenticated API call to our get payment (or get all payments) endpoint.

We POST the data as an application/x-www-form-urlencoded JSON string under the payload key.

Response

We expect a HTTP 200 status code from your server. Your response body will be ignored. If we do not receive a HTTP 200 we will retry the request multiple times over a period of 3 minutes.


Verifying payload authenticity

Once you have been provided with a Webhook Authentication Key it will be used to create a hash signature which will be sent along with all webhook payloads. You can use this signature to verify the authenticity of the payload received from us.

The hash is sent in the HTTP Authorization header and is computed by creating a HMAC hexdigest of the raw request body (ie. the original URL encoded body including the payload key) using SHA256.

The Authorization header will have the following form: SnapScan signature=<hash>, where <hash> will be replaced with the computed hash.

When comparing signatures we recommend you use constant time string comparison to avoid certain timing attacks, in Ruby this can be achieved using secure_compare.

An example of verifying the hash signature in Ruby:

params do
  requires :payload, String
end
post '/snapscan_webhook' do
  # the raw POST body that hasn't been parsed or decoded
  request_body = request.body.read
  verify_signature!(request_body, ENV['WEBHOOK_AUTH_KEY'])
  payload = JSON.parse(params[:payload])
  puts ">>> Received payload: #{payload.inspect}"
end

def verify_signature!(request_body, webhook_auth_key)
  signature = OpenSSL::HMAC.hexdigest('sha256', webhook_auth_key, request_body)
  auth_signature = "SnapScan signature=#{signature}"

  unless Rack::Utils.secure_compare(auth_signature, headers["Authorization"])
    raise "Unauthorized webhook received"
  end
end