WEBHOOKS

Get real-time information

What is a webhook?

A webhook is an API concept that’s growing in popularity. As more and more of what we do on the web can be described by events, webhooks are becoming even more applicable. They’re incredibly useful and a resource-light way to implement event reactions.

So, what exactly is a webhook? A webhook (also called a web callback or HTTP push API) is a way for an app to provide other applications with real-time information. A webhook delivers data to other applications as it happens, meaning you get data immediately. Unlike typical APIs where you would need to poll for data very frequently in order to get it real-time. This makes webhooks much more efficient for both provider and consumer. The only drawback to webhooks is the difficulty of initially setting them up.

Webhooks are sometimes referred to as “Reverse APIs,” as they give you what amounts to an API spec, and you must design an API for the webhook to use. The webhook will make an HTTP request to your app (typically a POST), and you will then be charged with interpreting it.

Consuming a Webhook

The first step in consuming a webhook is giving the webhook provider a URL to deliver requests to. This is most often done through a backend panel or an API. This means that you also need to set up a URL in your app that’s accessible from the public web.

The majority of webhooks will POST data to you in one of two ways: as JSON (typically) or XML (blech) to be interpreted, or as a form data (application/x-www-form-urlencoded or multipart/form-data). Your provider will tell you how they deliver it (or even give you a choice in the matter). Both of these are fairly easy to interpret, and most web frameworks will do the work for you. If they don’t, you may need to call on a function or two.

Security

Encryption

You may use a HTTP or a HTTPS url for webhooks. In most cases HTTP is sufficient, but HTTPS can be useful if your data is sensitive or if you wish to protect against replay attacks for example.

Authentication

Since anyone could in principle send request to your application, it’s important to verify that these webhooks are originated from Kushki. Valid webhooks will therefore contain these headers which contain a HMAC signature of the webhook payload (body):

1. KEY:

X-Kushki-Key: Kushki ID of the merchant (you can find it in our Backoffice system, Merchant Data section).

2. SIGNATURE you have to options:

  • X-Kushki-Signature: A HMAC SHA256 hex digest formed by signing the POST payload (body + timestamp) with the Webhook Signature ID (you can find it in our Backoffice system, Merchant Data section).

  • X-Kushki-SimpleSignature: A HMAC SHA256 hex digest formed by signing the POST payload (timestamp) with the Webhook Signature ID (you can find it in our Backoffice system, Merchant Data section).

3. ID

X-Kushki-Id: WebhookId of the request is the date in timestamp format.

Each merchant should compare the X-Pusher-Signature with the X-Pusher-Signature-expected that they find with HMAC-sha256 in the native language of their back-end application.

Examples:

PHP

// environment variable must be set
  $app_secret = getenv(KUSHKI_APP_SECRET');

  $app_key = $_SERVER['HTTP_X_KUSHKI_KEY'];
  $webhook_signature = $_SERVER ['HTTP_X_KUSHKI_SIGNATURE'];

  $body = file_get_contents('php://input');

  $expected_signature = hash_hmac( 'sha256', $body, $app_secret, false );

  if($webhook_signature == $expected_signature) {
    header("Status: 200 OK");
  }
  else {
    header("Status: 401 Not authenticated");
  }
?>

JAVA

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class HMAC {

  public static void main(String[] args) throws Exception {
    System.out.println(hmacDigest("payload_body + webhook_id + .", "key", "HmacSHA256"));
  }

  public static String hmacDigest(String msg, String keyString, String algo) {
    String digest = null;
    try {
      SecretKeySpec key = new SecretKeySpec((keyString).getBytes("UTF-8"), algo);
      Mac mac = Mac.getInstance(algo);
      mac.init(key);

      byte[] bytes = mac.doFinal(msg.getBytes("ASCII"));

      StringBuffer hash = new StringBuffer();
      for (int i = 0; i < bytes.length; i++) {
        String hex = Integer.toHexString(0xFF & bytes[i]);
        if (hex.length() == 1) {
          hash.append('0');
        }
        hash.append(hex);
      }
      digest = hash.toString();
    } catch (UnsupportedEncodingException e) {
    } catch (InvalidKeyException e) {
    } catch (NoSuchAlgorithmException e) {
    }
    return digest;
  }
}

NODE JS

Use Crypto library to generate the hash.

Documentation for crypto

var crypto = require('crypto')
  , text = 'I love cupcakes'
  , key = 'abcdeg'
  , hash

hash = crypto.createHmac('sha1', key).update(text).digest('hex')

Webhooks deliver the responses to your typeforms in JSON format. Let’s walk through our object in a webhook payload. First, you have to identify your integration:

You will find each payload.

Important Notice

Kushki stores your notifications on multiple servers to improve redundancy and achieve high availability. For this reason, on rare occasions, you might get a duplicate of a notification.

Remember to design the endpoint of your webhook to be idempotent (it should not be affected adversely when processing the same notification more than once).