Webhook Confirmation

This is how you'll confirm if a transfer charge has successfully processed

Introduction

When a transfer charge is successful, Transfers will make a POST request to an endpoint of your choosing (HTTPS only) with relevant information about the transfer in the request body.

Webhook Verification

When you set your Webhook URL during the onboarding process, a Signature Token will be generated. You'll use this to verify that requests to your Webhook URL are coming from Transfers and not a malicious actor.

Valid webhook requests have a header with the key X-Transfers-Signature which is an HMAC SHA256 signature of the request body (hex-encoded). The request body is signed using your Signature Token.

Steps

  • Sign the entire request body with HMAC SHA using the Signature Token.

  • Compare the result of this signing with the value of the X-Transfers-Signature

    header.

  • If they match, then the request is indeed from Transfers

Example with Ruby/Sinatra:

require 'sinatra'
require 'openssl'

post '/webhook' do
  signature_token = ENV['SIGNATURE_TOKEN']
  body = request.body.read
  hook_signature = request.env['HTTP_X_TRANSFERS_SIGNATURE']
  signature = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), signature_token, body)

  is_valid = Rack::Utils.secure_compare(signature, hook_signature)

  if is valid
    #do something with token
  end
end

Responding to a Webhook Request

  • You should respond to an event with 200 OK. We consider this an acknowledgement of the webhook by your application.

  • If your application responds with any status code outside of the 2xx range, we will consider it unacknowledged and thus continue to send the same webhook every few minutes.

  • You don't need to send a request body or some other parameter as it would be discarded - we only pay attention to the status code.

Webhook Request Body

"event": "Payment.Status",
    "data": {
        "status": "Completed", // or "Failed"
        "userId": "<your user's unique identifier>",
        "paymentReference": "<your transaction's unique identifier>",
        "amount": 100.23,
        "description": "Transaction Successful",
        "senderAccountName": "<bank account name of paying user>",
        "sourceAccountNumber": "<bank account number of paying user>",
        "sourceBankCode": "<bank code of paying user>",
        "destinationAccountNumber": "<bank account number of destination account>",
        "destinationBankCode": "<bank code of destination bank account>"
    }
}

You should use the senderAccountName provided in the response for a fraud check. This way, you can decide to not give value if the payment is coming from a bank account that doesn't match the verified name of your user.

Last updated