Agent skill
ComplyCube Webhooks Skill
Receive and verify ComplyCube webhooks. Use when setting up ComplyCube webhook handlers, debugging ComplyCube-Signature verification, or handling KYC/AML events like check.completed, check.completed.clear, client.created and workflow.session.completed.
Install this skill
npx skills add hookdeck/webhook-skills --skill complycube-webhooks
When to Use This Skill
- How do I receive ComplyCube webhooks?
- How do I verify the
ComplyCube-Signatureheader on a ComplyCube webhook? - How do I handle
check.completedorcheck.completed.clearevents? - Why is my ComplyCube webhook signature verification failing?
- Why was my ComplyCube webhook disabled?
Verification (core)
ComplyCube sends ComplyCube-Signature: <hex>: the bare lowercase hex HMAC-SHA256 of the raw request body, keyed with the webhook's secret (UTF-8 bytes, used as-is). There is no prefix, no timestamp and it is not the Standard Webhooks spec; only the body is signed. Verify over the raw bytes before parsing, validate the hex shape (64 chars) before decoding, then compare in constant time.
Node (Buffer.from(x, 'hex') silently drops invalid characters, so check the shape first):
const crypto = require('crypto');
function verifyComplyCubeSignature(rawBody, signatureHeader, secret) {
if (typeof signatureHeader !== 'string' || !/^[0-9a-f]{64}$/i.test(signatureHeader)) return false;
const expected = crypto.createHmac('sha256', secret).update(rawBody).digest();
return crypto.timingSafeEqual(Buffer.from(signatureHeader, 'hex'), expected);
}
Python (compare bytes so a non-ASCII header yields 401, not a 500):
import hashlib, hmac, re
def verify_complycube_signature(raw_body: bytes, signature_header: str | None, secret: str) -> bool:
if not signature_header or not re.fullmatch(r"[0-9a-fA-F]{64}", signature_header):
return False
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest().encode("ascii")
return hmac.compare_digest(signature_header.lower().encode("ascii"), expected)
Raw body matters. ComplyCube's own Node sample runs
bodyParser.json()and verifiesJSON.stringify(request.body), which only matches by accident when the re-serialised JSON is byte-identical. Verify the raw bytes instead. Express handlers useexpress.raw({ type: '*/*' }).
For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.
Reply 401 on a missing, malformed or mismatched signature.
Event Types
The event name is the body's type field (no header names the event). resourceType names the object in payload.
| Event | Triggered When |
|---|---|
check.completed | A check completed with any outcome |
check.completed.clear | A check completed with a clear outcome |
check.completed.attention | A check completed with an attention outcome |
check.completed.rejected | A check completed with a rejected outcome |
check.completed.match_ | A check completed with a match_confirmed outcome |
check.failed | A check failed |
client.created | A client was created |
workflow.session.completed | A workflow session completed |
A completed check fires both check.completed and the outcome-specific type if you subscribed to both. The full list of 25 types is in references/overview.md.
Delivery Behaviour
Return a 20x within 15 seconds. Otherwise ComplyCube retries up to 10 times with exponential backoff (60 s, 120 s, 480 s, ...) and then disables the webhook. Events can arrive more than once and out of order: use the event id for idempotency, and fetch the object from the API when you need its current state. Webhook URLs must be HTTPS.
Environment Variables
COMPLYCUBE_WEBHOOK_SECRET=your_webhook_secret # Returned once, when the webhook is created
Setup with Hookdeck
Create the webhook in ComplyCube with your Hookdeck source URL, then paste the webhook secret into the Hookdeck source's webhook verification settings (HMAC, SHA-256, header ComplyCube-Signature, hex). Hookdeck accepts the delivery quickly, which keeps you inside the 15-second window and avoids the webhook being disabled.
Local Development
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 complycube --path /webhooks/complycube
Reference Materials
- references/overview.md - Webhook concepts, event types and payload shape
- references/setup.md - Create a webhook endpoint and get its secret
- references/verification.md - Signature verification details and gotchas