Webhooks Guide

Listen for events on your ComplyCube account so your integration can automatically trigger reactions.

ComplyCube uses webhooks to notify your application when an event happens in your account. Webhooks are particularly useful for asynchronous events like when a check has concluded.

Not all ComplyCube integrations require webhooks. Keep reading to learn more about what webhooks are and when you should use them.

What are webhooks?

Webhooks refers to a combination of elements that collectively create a notification and reaction system within a larger integration.

Metaphorically, webhooks are like a phone number that ComplyCube calls to notify you of your account activity. The activity could be that a document check is complete. The webhook endpoint is the person answering that call who takes actions based upon the specific information it receives.

Non-metaphorically, the webhook endpoint is just more code on your server. The webhook endpoint has an associated URL (e.g., https://example.com/webhooks). The ComplyCube notifications are Event objects. This object contains all the relevant information about what just happened, including the type of event and the data associated with that event. The webhook endpoint uses the event details to take any required actions, such as putting a temporary hold on a customer's account or transaction.

What are the components of a webhook?

ComplyCube Webhooks integration includes the following:

  • Events. An action or change in data that generates notifications. Webhooks can be used to create alerts that trigger these events. For the list of support events types, see the Webhooks API page.

  • Subscriptions. Configured in the developer portal or via API to subscribe to notifications associated with a specific event type.

  • Notification URL. The configurable service in the application to which alerts are sent.

  • Notification body. Details about the object associated with the event.

When to use webhooks?

Many events that occur within the ComplyCube account have synchronous results – immediate and direct – to an executed request. For example, a successful request to create a client immediately returns a client object. Such requests don’t require webhooks, as the key information is already available.

On the other hand, Checks are asynchronous: happening later and not directly in response to your code’s execution. With these events, ComplyCube needs to notify your integration about changes to an object's status, so your integration can take subsequent steps.

The specific actions your webhook endpoint may take differs based upon the event. Some examples include:

  • Decide to accept or reject a customer's request to be on-boarded onto your platform based on a check outcome.

  • Alerted by our continuous monitoring engine when a customer has a potential match, as we update our databases in realtime.

Verify the webhook signatures using our official libraries

ComplyCube signs the webhook events it sends to your endpoints by including a signature in each event’s ComplyCube-Signature header. This allows you to verify that the events were sent by ComplyCube, not by a third party. You can verify signatures either using our official libraries or manually using your own solution.

Use one of our official libraries to verify signatures. You perform the verification by providing the event payload, the ComplyCube-Signature header, and the endpoint’s secret. If verification fails, ComplyCube returns an error.

const { EventVerifier } = require('@complycube/api')
// Provide your webhook secret to the EventVerifier
const webhookSecret = process.env.COMPLYCUBE_WEBHOOK_SECRET;
const eventVerifier = new EventVerifier(webhookSecret);
// This example uses Express to receive webhooks
const app = require('express')();
// Use body-parser to retrieve the raw body as a buffer
const bodyParser = require('body-parser');
// Match the raw body to content type application/json
app.post('/webhook', bodyParser.json(), (request, response) => {
const signature = request.headers['complycube-signature'];
let event;
try {
event = eventVerifier.constructEvent(JSON.stringify(request.body), signature);
catch (err) {
response.status(400).send(`Webhook Error: ${err.message}`);
// Handle the event
switch (event.type) {
case 'check.completed': {
const checkId = event.payload.id;
const checkOutCome = event.payload.outcome;
console.log(`Check ${checkId} completed with outcome ${checkOutCome}`);
case 'check.pending': {
const checkId = event.payload.id;
console.log(`Check ${checkId} is pending`);
// ... handle other event types
default: {
// Unexpected event type
return response.status(400).end();
// Return a response to acknowledge receipt of the event
response.json({received: true});
app.listen(4242, () => console.log('Running on port 4242'));
import json
import flask
from flask import request
import complycube.eventverifier as ccevnt
# Sample flask app
app = flask.Flask(__name__)
# Provide your webhook secret to the EventVerifier
verifier = ccevnt.EventVerifier(os.getenv('COMPLYCUBE_WEBHOOK_SECRET'))
@app.route('/webhook', methods=['POST'])
def webhook():
if not request.headers.has_key('Complycube-Signature'):
return jsonify({'received':'False'}), 400
signature = request.headers['Complycube-Signature']
event = verifier.construct_event(request.get_data(),signature)
check_id = event.payload['id']
if event.type == 'check.completed':
check_outcome = event.payload['outcome']
print('Check %s completed with outcome %s' % (check_id,check_outcome))
elif event.type == 'check.pending':
print('Check %s is pending' % check_id)
# ... Handle other expected events
return jsonify({'received':'False'}), 400
except ccevnt.VertificationError:
return jsonify({'received':'False'}), 400
return jsonify({'received':'True'}), 200
use ComplyCube\ComplyCubeClient;
use ComplyCube\Model\Event;
use ComplyCube\EventVerifier;
use ComplyCube\Exception\VerificationException;
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: POST");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Authorization, Complycube-Signature, X-Requested-With");
define("SIGNATURE_KEY", 'Complycube-Signature');
$data = file_get_contents('php://input');
$verifier = new \ComplyCube\EventVerifier('WEBHOOK_SECRET');
$headers = apache_request_headers();
try {
if (!isset($headers[SIGNATURE_KEY])) {
$event = $verifier->constructEvent($data, $headers[SIGNATURE_KEY]);
switch ($event->type) {
case "check.completed":
$outcome = $event->payload->outcome;
# do completed check processing
case "check.pending":
# do pending check processing
} catch (\ComplyCube\Exception\VerificationException $e) {
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
namespace ComplyCube.Net.Example.Controllers
public class CCEventsController : ControllerBase
public IActionResult Post([FromBody] string payload)
var re = Request;
StringValues payloadSignature;
re.Headers.TryGetValue("ComplyCube-Signature", out payloadSignature);
var evr = new EventVerifier("WEBHOOK_SECRET");
var receivedEvent = evr.ConstructEvent(payload, payloadSignature);
switch (receivedEvent.type)
case "check.completed":
object outcome;
if(receivedEvent.payload.TryGetValue("outcome", out outcome))
// do completed check processing
case "check.pending":
// do pending check processing
return StatusCode(400);
return (StatusCode(200, receivedEvent));

Verify the webhook signatures manually

ComplyCube generates signatures using a hash-based message authentication code (HMAC) with SHA-256. Although it’s recommended to use our official libraries to verify webhook event signatures, you can create a custom solution by following these steps.

  1. Extract the complycube-signature from the HTTP headers.

  2. Determine the expected signature by computing an HMAC with the SHA256 hash function. Use your webhook's secret as the key, and use the request body string as the message.

  3. Compare the signature in the header to the expected signature.

Best Practices

Event types

You should configure your webhook endpoints to receive only the types of events required by your integration. Listening for extra events (or all events) will put undue strain on your server and is not recommended.

You can change the events a webhook endpoint will receive in the Dashboard or with the API.

Handle duplicate events

Webhook endpoints might occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is by logging the events you’ve processed and then not processing already-logged events.

Order of events

ComplyCube does not guarantee the delivery of events in the order in which they are generated. Your endpoint should not expect delivery of events in a given order and should handle this accordingly. You can also use the API to fetch any missing objects.

Receive events with an HTTPS server

If you use an HTTPS URL for your webhook endpoint, ComplyCube will validate that your server's connection is secure before sending your webhook data. For this to work, you must correctly configure your server to support HTTPS with a valid server certificate.