Webhooks

Receive notifications on time using webhooks.

Webhooks are used to notify you about the changes in statuses for KYC/KYB applicants and transactions.

The following webhook types are available:

🚧

Mind the following:

  • We do not send any information to endpoints using HTTP, only HTTPS.
  • Not receiving an answer from a webhook endpoint for more than 5 seconds is considered to be a timeout, and our service will try to resend the same webhook later.
  • Supported versions of TLS protocol are 1.2 or higher.
  • When a webhook HTTP request fails, we attempt to resend it four times: after 5 minutes, 1 hour, 5 and 18 hours until request succeeds. We also send an email notification informing you about the failed webhook event.
  • Check the createdAtMs field of the webhook payload to make sure that you are getting the relevant applicant status.

Create webhooks

To create a webhook:

  1. in the Dashboard, go to the Webhooks page and click Create webhook.
  2. Provide a preferable webhook name.
  3. Select a webhook receiver type, which can be any HTTP address, Slack, Telegram, or email.
  4. Specify the target endpoint where webhooks are expected to be received. Depending on the selected receiver type, you can specify an HTTP address, Slack webhook URL, Telegram API token with Telegram chat ID after @, or email.
  5. Select a webhook type. For more information, see user verification webhooks and transaction monitoring webhooks.
  6. Select an applicant type for which to send the webhook.
  7. Specify a secret key to be used to calculate the digest with the HMAC algorithm.
  8. Select a signature algorithm to be used when verifying the webhook sender.
  9. Add custom headers if necessary. Available only if HTTP address is set as the webhook receiver type.
  10. [Optionally] Select a source key. Available only if at least one source key is configured in your environment.
  11. Enable the Resend failed webhooks several times toggle to enable/disable sending failed webhooks repeatedly.
  12. Click Test webhook to see how it performs.
  13. Save your changes.

Verify webhook sender

To make sure the webhook is sent by Sumsub, we sign it with the HMAC algorithm.

🚧

Important

To use this feature, set a Secret Key value when creating a webhook.

We also send the additional X-Payload-Digest-Alg header that specifies one of the following algorithms to be used:

  • HMAC_SHA1_HEX (legacy, deprecated)
  • HMAC_SHA256_HEX (default upon creating a new webhook)
  • HMAC_SHA512_HEX

You can choose among these algorithms when setting up your webhooks.

To verify the webhook sender:

  1. Get a webhook x-payload-digest header value and payload as it is, without any alteration or converting to JSON.
  2. Receive the HTTP webhook body in bytes.
  3. Calculate the digest with the raw webhook payload in bytes and the HMAC algorithm specified in the x-payload-digest-alg header.
  4. Compare the x-payload-digest header value with the calculated digest.

πŸ“˜

Note

  • Do not rely on our IP addresses for whitelisting them as the webhook sender because they can change.
  • Make sure to test your webhooks before sending its URL to us. At a minimum, it should not give a 500 HTTP response or require any sort of authorization.

To check that you compute the digest the same way we do, use the following POST method:

curl -X POST \
  'https://api.sumsub.com/resources/inspectionCallbacks/testDigest?secretKey=SoMe_SeCrEt_KeY&digestAlg=HMAC_SHA1_HEX' \
  -H 'Content-Type: text/plain' \
  -d 'someText'
NameTypeRequiredDescriptionDefault
# {body}ObjectYesAny payload.N/A
secretKeyStringYesA secret key that can be used for signing.N/A
digestAlgStringNoA signature algorithm that can be used for signing. Possible values: HMAC_SHA1_HEX, HMAC_SHA256_HEX, HMAC_SHA512_HEX.HMAC_SHA1_HEX

Response

{
  "digest": "f6e92ffe371718694d46e28436f76589312df8db",
  "digestAlg": "HMAC_SHA1_HEX"
}

Example request to the client endpoint

curl -X POST \
  'https://callbackurl.com/kyc' \
  -H 'Content-Type: application/json' \
  -d '{
    "applicantId": "5cb56e8e0a975a35f333cb83",
    "inspectionId": "5cb56e8e0a975a35f333cb84",
    "correlationId": "req-ec508a2a-fa33-4dd2-b93d-fcade2967e03",
    "externalUserId": "12672",
    "type": "applicantReviewed",
    "reviewResult": {
        "reviewAnswer": "GREEN"
    },
    "reviewStatus": "completed",
    "createdAtMs": "2020-02-21 13:23:19.111",
    "clientId": "SumsubClient"
}'

Example of computing the digest

export function checkDigest(req): boolean {
 const algo = {
  'HMAC_SHA1_HEX': 'sha1',
  'HMAC_SHA256_HEX': 'sha256',
  'HMAC_SHA512_HEX': 'sha512',
 }[req.headers['X-Payload-Digest-Alg']]

 if (!algo) {
  throw new Error('Unsupported algorithm')
 }

 const calculatedDigest = crypto
  .createHmac(algo, SUMSUB_PRIVATE_KEY)
  .update(req.rawBody)
  .digest('hex')

 return calculatedDigest === req.headers['x-payload-digest']
}
private async Task<bool> CheckDigest(HttpRequest request)
{
    using (var reader = new StreamReader(request.Body))
    {
        var body = await reader.ReadToEndAsync();
        byte[] byteArray = Encoding.UTF8.GetBytes(body);
        using (MemoryStream stream = new MemoryStream(byteArray))
        {
            string algo = request.Headers["x-payload-digest-alg"];
            string calculateDigest = string.Empty;

            switch (algo)
            {
                case "HMAC_SHA1_HEX":
                    using (var hmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(_verificationAccessor.SumSubPrivateKey)))
                    {
                        calculateDigest = hmacsha1.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}", e));
                    }
                    break;
                case "HMAC_SHA256_HEX":
                    using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_verificationAccessor.SumSubPrivateKey)))
                    {
                        calculateDigest = hmacsha256.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}", e));
                    }
                    break;
                case "HMAC_SHA512_HEX":
                    using (var hmacsha512 = new HMACSHA512(Encoding.UTF8.GetBytes(_verificationAccessor.SumSubPrivateKey)))
                    {
                        calculateDigest = hmacsha512.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}", e));
                    }
                    break;
                default:
                    using (var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes(_verificationAccessor.SumSubPrivateKey)))
                    {
                        calculateDigest = hmacsha256.ComputeHash(stream).Aggregate("", (s, e) => s + String.Format("{0:x2}", e));
                    }
                    break;
            }

            return calculateDigest == request.Headers["x-payload-digest"];
        }
    }
}
public function validateWebHook(HttpRequest $request, string $content): void
{
    $algo = match($request->headers->get('X-Payload-Digest-Alg')) {
      'HMAC_SHA1_HEX' => 'sha1',
      'HMAC_SHA256_HEX' => 'sha256',
      'HMAC_SHA512_HEX' => 'sha512',
      default => throw new \RuntimeException('Unsupported algorithm'),
    };

    $res = $request->headers->get('X-Signature') === hash_hmac(
        $algo,
        $content,
        'your_secret_key'
    );

    if (!$res) {
        $this->logger->error('Webhook sumsub sign ' . $content);
        throw new LogicProfileException('Webhook sumsub sign ' . $content);
    }
}

Get webhooks with Telegram

To receive webhooks in Telegram:

  1. Create a Telegram bot with BotFather.
  2. Save the bot token.
  3. Create a new group and invite the bot to this group.
  4. Get the list of updates for your bot using: https://api.telegram.org/bot<YourBOTToken>/getUpdates.
  5. Paste the bot token and chatId into the Target field of the webhook configuration and save it.

Manage webhook settings

You can manage your webhooks settings in any of the following ways:

  • Edit webhook parameters. Lets you edit webhook parameters at any time if you need to change some of the existing webhook settings.
  • Remove webhooks. Lets you remove a webhook configuration at any time in case you no longer need it.
  • Disable webhooks. Lets you disable the webhook. You can reenable it at any time.