Skip to main content
In a nutshell: Webhooks allow you to set up a notification system that can be used to receive updates on certain requests made to the Adhere API.
Adhere uses webhooks to notify your application when specific events occur. This allows you to build automated workflows and integrate Adhere closely with your system.

Why use Webhooks?

Generally, when you make a request to an API endpoint, you expect to get a near-immediate response. However, some requests may take a long time to process. In order to prevent a timeout error, a pending response is returned. Since your records need to be updated with the final state of the request, you need to either:
  1. Polling: Make a request for an update at regular intervals.
  2. Webhooks: Listen to events by using a webhook URL.
We recommend using webhooks over polling. Webhooks are more efficient, reduce network overhead, and ensure your system is updated immediately when an event occurs.

Setup & Integration

To start receiving webhook notifications, follow these steps to configure your environment:
1

Configure Webhook URL

Provide the endpoint on your server where Adhere will send POST requests. This should be a publicly accessible URL.
2

Set Hash Key

A secret key used to sign the webhook payload. You must keep this secure and use it to verify that requests are coming from Adhere.
3

Save Configuration

Save your settings in the Adhere dashboard under the Integrations section.

Security & Verification

All webhook requests from Adhere include a X-Hub-Signature header. This header contains the HMAC SHA256 signature of the request body, signed with your Hash Key.

Verifying Signatures

To ensure that a webhook request is genuinely from Adhere, you should verify the signature before processing the payload.
import hmac
import hashlib
import base64
from flask import request, abort

def verify_webhook(request, hash_key):
    sig_header = request.headers.get("X-Hub-Signature")
    if not sig_header:
        abort(401, "Missing signature")

    # The header format is "sha256=<signature>"
    _, _, received_sig = sig_header.partition("=")

    # Compute the HMAC SHA256 digest of the raw request body
    raw_body = request.get_data()
    digest = hmac.new(
        hash_key.encode("utf-8"),
        raw_body,
        hashlib.sha256
    ).digest()

    expected_sig = base64.b64encode(digest).decode("utf-8")

    if not hmac.compare_digest(received_sig, expected_sig):
        abort(401, "Invalid signature")
Always verify the X-Hub-Signature header to prevent unauthorized requests from interacting with your server.

Event Payload Structure

All webhooks follow a consistent JSON structure:
ParameterTypeDescription
successbooleanIndicates if the event was processed successfully.
modulestringThe Adhere module that triggered the event (e.g., transaction_monitoring, kyc).
eventstringThe specific event type.
dataobjectThe actual payload data (e.g., transaction details, KYC results).

Supported Events

Transaction Monitoring

  • Module: transaction_monitoring
  • Events:
    • suspicious_transaction: Triggered when a transaction is processed and deemed suspicious.
      {
        "data": {
          "id": 23,
          "is_internal_blacklisted": false,
          "is_blacklisted_by": null,
          "case_id": "#8N2ZI6",
          "case_sla": "2025-08-23T09:39:31.551479Z",
          "case_status": "open",
          "transaction_id": "9201634916397893719",
          "amount": 12345.0,
          "currency": "EUR",
          "transaction_type": "card",
          "account_type": "individual",
          "customer_name": "David Seaman",
          "customer_email": "[email protected]",
          "customer_ip_address": "192.168.0.8",
          "customer_location": "Yaba, LG",
          "origin_account_no": "4321567809",
          "origin_bank_code": "327",
          "transaction_description": "Payment for order #78901",
          "destination_account_no": "0123456789",
          "destination_bank_code": "723",
          "merchant_name": null,
          "merchant_location": null,
          "status": "suspicious",
          "card_bin": null,
          "card_last4": null,
          "bvn": "7890123456",
          "fraud_percent": null,
          "tag": [
            "1 rule(s) triggered"
          ],
          "sender_blacklisted": false,
          "receiver_blacklisted": false,
          "rules_flagged": [
            "Any transaction by an individual that exceeds an amount {a}"
          ],
          "additional_info": {},
          "date_created": "2025-08-20T09:39:31.425545Z",
          "date_updated": "2026-01-16T13:46:07.388489Z",
          "branch": 2
        },
        "event": "suspicious_transaction",
        "module": "transaction_monitoring",
        "success": true
      }
      

Testing Locally

Before deploying to production, we recommend testing your webhook implementation locally.
  1. Use ngrok: Use ngrok to create a secure tunnel to your local server.
  2. Set Webhook URL: Update your Adhere dashboard with the ngrok URL (e.g., https://your-subdomain.ngrok-free.app/webhooks).
  3. Inspect Requests: Use the ngrok dashboard or Webhook.site to inspect the payloads and headers sent by Adhere.

Best Practices

  • Acknowledge Immediately: Your server should return a 200 OK response as quickly as possible. Heavy processing should be handled asynchronously using a task queue.
  • Handle Retries: Adhere will retry failed webhook deliveries (non-2xx responses) up to 3 times with an exponential backoff.
  • Use Idempotency: Ensure your system can handle the same webhook multiple times safely. Use the event’s unique ID to track processed events.
If your server does not return a 2xx response, Adhere will consider the delivery as failed and will attempt to retry.