Language
Tools
Step 3: Validating webhooks
Assume that you own an e-commerce site and a customer has just made a purchase and the following webhook has been posted to your system.
The topic
field of an event holds a description of the event, which is similar the subject of an e-mail message. The webhook
itself contains _links
to the resource impacted by the event that can be used to retrieve more information about the webhook you have received.
NOTE: The event
must be retrieved with a client_credentials
granted access_token.
JSON
{
"topic": "buygoods_transaction_received",
"id": "2133dbfb-24b9-40fc-ae57-2d7559785760",
"created_at": "2020-10-22T10:43:20+03:00",
"event": {
"type": "Buygoods Transaction",
"resource": {
"id": "458712f-gr76y-24b9-40fc-ae57-2d35785760",
"amount": "100.0",
"status": "Received",
"system": "Lipa Na M-PESA",
"currency": "KES",
"reference": "OJM6Q1W84K",
"till_number": "000000",
"sender_phone_number": "+254999999999",
"hashed_sender_phone": "8f7bd03d28bb39ffbe7e074ad6a85352b4de2c8a8af1db7db7e5a520e37e015d",
"origination_time": "2020-10-22T10:43:19+03:00",
"sender_last_name": "Doe",
"sender_first_name": "Jane",
"sender_middle_name": null
}
},
"_links": {
"self": "https://sandbox.kopokopo.com/webhook_events/2133dbfb-24b9-40fc-ae57-2d7559785760",
"resource": "https://sandbox.kopokopo.com/financial_transaction/458712f-gr76y-24b9-40fc-ae57-2d35785760"
}
}
- The hashed_sender_phone field will be returned within the resource payload by K2Connect SDKs in the near future.
Step 3A. Authenticating the webhook request
Before we process any data from the webhook we’ll want to validate that the request really came from Kopo Kopo and not someone pretending to be Kopo Kopo. Kopo Kopo signs each webhook request with the api_key
you got when creating an oauth application. The signature is contained in the X-KopoKopo-Signature
header and is a SHA256 HMAC hash of the request body with the key being your client secret.
You can validate the webhook by generating the same SHA256 HMAC hash and comparing it to the signature sent with the payload.
webhook_test = K2Client.new(API_KEY)
webhook_test.parse_request(request)
K2Authenticator.authenticate(webhook_test.hash_body, webhook_test.api_secret_key, webhook_test.k2_signature)
not available
const Webhooks = K2.Webhooks
//Router or whatever server you are using
// This is the endpoint you used when subscribing
router.post('/buygoodsreceived', function(req, res, next){
// This will both validate and process the payload for you
Webhooks
.webhookHandler(req, res)
.then( response => {
console.log(response)
})
.catch( error => {
console.log(error)
})
})
k2connect.initialize(CLIENT_ID, CLIENT_SECRET, BASE_URL)
result_handler = k2connect.ResultHandler
processed_payload = result_handler.process(request)
<?
$webhooks = $K2->Webhooks();
$webhook_payload = file_get_contents('php://input');
// This will both validate and process the payload for you
$response = $webhooks->webhookHandler($webhook_payload, $_SERVER['HTTP_X_KOPOKOPO_SIGNATURE']);
echo json_encode($response);
Step 3B. Check for duplicate events (eg. duplicate transactions)
It is important to consider that it is possible for your system to receive the same webhook more than once and you should be able to handle duplicates on your end.
To do this, keep a queue of events in a database and check to see if an Event
has the same self
resource location in _links
as another event. If not, process the logic for that event. To illustrate, this is how a developer would implement this using Ruby and the ActiveRecord ORM.
Ruby/ActiveRecord
# Assuming you have an ActiveRecord model called KopoKopoTransaction
unless KopoKopoTransaction.where(resource_id: 'cdb5f11f-62df-e611-80ee-0aa34a9b2388').first
# do something
end