Complyance Logo

Setup and Configuration

This guide covers how to create a purchase invoice webhook in your Complyance workspace and configure it for secure event delivery.

Before You Begin

Make sure you have:

  • Access to the correct Complyance workspace
  • A backend endpoint that can accept POST requests
  • HTTPS enabled for production use
  • A plan for storing and rotating webhook secrets securely

Step 1: Open the Webhooks Area

Navigate to your workspace and open the Webhooks section.

Step 2: Create a New Webhook

Click New Webhook and complete the initial configuration fields.

FieldRequiredDescription
Webhook NameYesA descriptive name for internal identification
CountryYesOne supported country: AE, SA, MY, DE, or BE
Webhook URLYesThe HTTPS endpoint that will receive webhook deliveries
EnvironmentYesChoose sandbox or production

Environment Selection Note

Choose the environment carefully when creating the webhook. The environment selector locks after creation and cannot be changed later.

Step 3: Enable HMAC Signing

HMAC signing is strongly recommended for all webhook integrations.

  1. Turn HMAC Signing on
  2. Select a signing algorithm
  3. Copy and securely store the generated secret

Supported signing algorithms:

  • SHA-256 recommended
  • SHA-512

Secret Management Note

The signing secret is shown only once during setup and cannot be retrieved later. If the secret is lost, you will need to regenerate it and update your receiving service.

Signature Verification

When HMAC signing is enabled, Complyance includes an X-Webhook-Signature header with each webhook delivery. Your receiver should verify this signature before trusting or processing the payload.

Why Verification Matters

Signature verification helps ensure that:

  • The webhook was sent by a trusted source
  • The payload was not modified in transit
  • Your endpoint does not process forged requests

Verification Steps

  1. Read the raw request body exactly as received
  2. Load the signing secret captured during webhook creation
  3. Compute an HMAC digest over the raw body using the configured algorithm
  4. Compare your computed digest with X-Webhook-Signature using a timing-safe comparison

Important Implementation Detail

Use the raw JSON request body, not a reformatted, parsed, or pretty-printed version of the payload. Even harmless formatting changes can produce a different digest and cause signature verification to fail.

Node.js / TypeScript Example

import { createHmac, timingSafeEqual } from 'crypto';

function verifyWebhookSignature(rawBody: string, secret: string, signatureHeader: string) {
  const expected = createHmac('sha256', secret)
    .update(rawBody, 'utf8')
    .digest('hex');

  return timingSafeEqual(
    Buffer.from(signatureHeader, 'hex'),
    Buffer.from(expected, 'hex')
  );
}

Python Example

import hmac
import hashlib

def verify_webhook_signature(raw_body: str, secret: str, signature_header: str) -> bool:
    expected = hmac.new(
        secret.encode('utf-8'),
        raw_body.encode('utf-8'),
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature_header)

Java Example

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;

public static boolean verifyWebhookSignature(String rawBody, String secret, String signatureHeader) {
    try {
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
        String expected = bytesToHex(mac.doFinal(rawBody.getBytes("UTF-8")));
        return MessageDigest.isEqual(expected.getBytes(), signatureHeader.getBytes());
    } catch (Exception e) {
        return false;
    }
}

Go Example

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
)

func verifyWebhookSignature(rawBody, secret, signatureHeader string) bool {
    mac := hmac.New(sha256.New, []byte(secret))
    mac.Write([]byte(rawBody))
    expected := hex.EncodeToString(mac.Sum(nil))
    return hmac.Equal([]byte(expected), []byte(signatureHeader))
}

PHP Example

function verifyWebhookSignature(string $rawBody, string $secret, string $signatureHeader): bool {
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signatureHeader);
}

.NET Example

using System.Security.Cryptography;
using System.Text;

bool VerifyWebhookSignature(string rawBody, string secret, string signatureHeader)
{
    using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
    var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(rawBody));
    var expected = Convert.ToHexString(hash).ToLower();
    return CryptographicOperations.FixedTimeEquals(
        Encoding.UTF8.GetBytes(expected),
        Encoding.UTF8.GetBytes(signatureHeader)
    );
}

Security Best Practices

  • Keep the signing secret in a secure secret store or server-side environment variable
  • Rotate secrets when there is any suspicion of exposure
  • Reject requests with invalid signatures before business processing
  • Avoid logging raw secrets or full sensitive payloads
  • Keep webhook endpoints server-side only, never in browser code

Operational Recommendation

Return an error response when signature verification fails, and make sure those failures are monitored. Invalid-signature patterns are often your earliest signal of a misconfiguration or malicious traffic.

Step 4: Select Events

Choose the purchase invoice events your endpoint should receive:

  • purchase.invoice.stored
  • purchase.invoice.validation_failed

Depending on the UI flow, you may also see quick presets such as:

  • All Events
  • Financial Events
  • Category-based event selection

For a focused integration, subscribe only to the purchase invoice events your system is prepared to process.

Step 5: Create the Webhook

Click Create Webhook to save the configuration and activate deliveries for the selected environment and country.

  • Use separate webhook endpoints for sandbox and production
  • Keep webhook naming descriptive so teams can identify ownership easily
  • Store signing secrets in environment variables or a secrets manager
  • Restrict endpoint access to server-side infrastructure only
  • Log delivery receipt, event type, and event ID for support and audits

Operational Checklist

Before going live, confirm that your receiver:

  • Returns a successful HTTP response quickly
  • Verifies signatures before processing
  • Handles duplicate deliveries safely
  • Stores the event ID for idempotency
  • Captures failed deliveries in logs or monitoring