Webhook Events
Zenoo sends webhook events to your configured endpoint when significant actions occur in the CLM platform. Use webhooks to build real-time integrations, trigger workflows, and keep external systems in sync.
Event delivery
| Property | Value |
|---|
| Method | POST |
| Content-Type | application/json |
| Signature header | X-Zenoo-Signature (HMAC-SHA256) |
| Retry schedule | 1 min, 5 min, 30 min, 2 hr, 24 hr |
| Idempotency | Each event has a unique event_id |
| Timeout | 30 seconds (your endpoint must respond) |
Always verify the X-Zenoo-Signature header before processing webhook payloads. See the signature verification section below.
Event types
Case events
| Event | Trigger |
|---|
case.created | New case created |
case.status_changed | Case status transition |
case.closed | Case closed with resolution |
case.escalated | Case escalated to a manager |
Alert events
| Event | Trigger |
|---|
alert.created | New alert generated from check result |
alert.resolved | Alert resolved by analyst or auto-disposition |
alert.escalated | Alert escalated to manager |
alert.ai_research_completed | AI research completed for alert |
Check events
| Event | Trigger |
|---|
check.completed | Check execution completed with result |
check.failed | Check execution failed |
Risk events
| Event | Trigger |
|---|
risk_assessment.completed | Risk assessment scoring completed |
risk_assessment.approved | Risk assessment approved by reviewer |
SLA events
| Event | Trigger |
|---|
sla.warning | Case approaching SLA deadline (warning threshold) |
sla.breached | Case has passed its SLA deadline |
Common envelope
Every webhook event uses this envelope structure:
{
"event_id": "evt_abc123xyz",
"event_type": "case.created",
"created_at": "2026-02-16T10:01:00Z",
"data": {
// Event-specific payload
}
}
| Field | Type | Description |
|---|
event_id | string | Unique event identifier for idempotency |
event_type | string | Event type string |
created_at | string | ISO 8601 timestamp of event creation |
data | object | Event-specific payload (varies by type) |
Event payloads
case.created
{
"event_id": "evt_001",
"event_type": "case.created",
"created_at": "2026-02-16T10:01:00Z",
"data": {
"case_token": "cas_xyz789",
"type": "Onboarding",
"status": "New",
"priority": "Medium",
"entity_token": "ent_abc123",
"entity_name": "Acme Holdings Ltd",
"due_date": "2026-03-02T10:00:00Z"
}
}
case.status_changed
{
"event_id": "evt_002",
"event_type": "case.status_changed",
"created_at": "2026-02-16T10:30:00Z",
"data": {
"case_token": "cas_xyz789",
"old_status": "New",
"new_status": "In Progress",
"changed_by": { "id": "user_analyst01", "name": "Sarah Johnson" }
}
}
case.closed
{
"event_id": "evt_003",
"event_type": "case.closed",
"created_at": "2026-02-16T11:35:00Z",
"data": {
"case_token": "cas_xyz789",
"risk_tier": "Medium",
"risk_score": 45,
"resolution_notes": "All checks passed. PEP match reviewed and cleared.",
"closed_by": { "id": "user_analyst01", "name": "Sarah Johnson" }
}
}
case.escalated
{
"event_id": "evt_004",
"event_type": "case.escalated",
"created_at": "2026-02-16T12:00:00Z",
"data": {
"case_token": "cas_xyz789",
"escalated_by": { "id": "user_analyst01", "name": "Sarah Johnson" },
"escalated_to": { "id": "user_manager01", "name": "Mike Chen" },
"reason": "Complex corporate structure requires senior review."
}
}
alert.created
{
"event_id": "evt_005",
"event_type": "alert.created",
"created_at": "2026-02-16T10:15:00Z",
"data": {
"alert_token": "alt_001",
"case_token": "cas_xyz789",
"type": "Screening",
"category": "PEP Match",
"title": "PEP Match: John Doe",
"priority": "High",
"priority_score": 78,
"entity_name": "John Doe"
}
}
alert.resolved
{
"event_id": "evt_006",
"event_type": "alert.resolved",
"created_at": "2026-02-16T11:30:00Z",
"data": {
"alert_token": "alt_001",
"case_token": "cas_xyz789",
"status": "Resolved",
"resolution_action": "Approve",
"resolution_notes": "Former local councillor. Low risk.",
"resolved_by": { "id": "user_analyst01", "name": "Sarah Johnson" }
}
}
alert.escalated
{
"event_id": "evt_007",
"event_type": "alert.escalated",
"created_at": "2026-02-16T12:00:00Z",
"data": {
"alert_token": "alt_002",
"case_token": "cas_xyz789",
"escalated_by": { "id": "user_analyst01", "name": "Sarah Johnson" },
"escalated_to": { "id": "user_manager01", "name": "Mike Chen" },
"reason": "Potential sanctions match requires senior review."
}
}
alert.ai_research_completed
{
"event_id": "evt_008",
"event_type": "alert.ai_research_completed",
"created_at": "2026-02-16T10:05:30Z",
"data": {
"alert_token": "alt_001",
"confidence": 85,
"false_positive_probability": 82,
"recommended_action": "Approve"
}
}
check.completed
{
"event_id": "evt_009",
"event_type": "check.completed",
"created_at": "2026-02-16T10:10:12Z",
"data": {
"check_token": "chk_001",
"case_token": "cas_xyz789",
"type": "PEP Screening",
"category": "Screening",
"result": "Refer",
"provider": "WorldCheck",
"entity_name": "John Doe",
"alert_generated": true,
"alert_token": "alt_001"
}
}
check.failed
{
"event_id": "evt_010",
"event_type": "check.failed",
"created_at": "2026-02-16T10:12:00Z",
"data": {
"check_token": "chk_003",
"case_token": "cas_xyz789",
"type": "Company Registry",
"category": "Company",
"error": "Provider timeout after 30 seconds",
"retry_scheduled": true,
"retry_count": 1
}
}
risk_assessment.completed
{
"event_id": "evt_011",
"event_type": "risk_assessment.completed",
"created_at": "2026-02-16T11:00:00Z",
"data": {
"assessment_token": "rsk_001",
"case_token": "cas_xyz789",
"overall_tier": "Medium",
"overall_score": 45,
"customer_risk": { "score": 40, "tier": "Medium" },
"geographic_risk": { "score": 30, "tier": "Low" },
"product_risk": { "score": 55, "tier": "Medium" },
"channel_risk": { "score": 25, "tier": "Low" },
"edd_required": false
}
}
risk_assessment.approved
{
"event_id": "evt_012",
"event_type": "risk_assessment.approved",
"created_at": "2026-02-16T11:15:00Z",
"data": {
"assessment_token": "rsk_001",
"case_token": "cas_xyz789",
"approved_by": { "id": "user_manager01", "name": "Mike Chen" },
"overall_tier": "Medium"
}
}
sla.warning
{
"event_id": "evt_013",
"event_type": "sla.warning",
"created_at": "2026-02-28T01:00:00Z",
"data": {
"case_token": "cas_xyz789",
"due_date": "2026-03-02T10:00:00Z",
"days_remaining": 2,
"assigned_to": { "id": "user_analyst01", "name": "Sarah Johnson" }
}
}
sla.breached
{
"event_id": "evt_014",
"event_type": "sla.breached",
"created_at": "2026-03-03T01:00:00Z",
"data": {
"case_token": "cas_xyz789",
"due_date": "2026-03-02T10:00:00Z",
"days_overdue": 1,
"auto_escalated": true,
"escalated_to": { "id": "user_manager01", "name": "Mike Chen" }
}
}
Signature verification
Verify the webhook signature to ensure the payload is authentic:
import hmac
import hashlib
def verify_signature(payload_bytes, signature, secret):
expected = hmac.new(
secret.encode("utf-8"),
payload_bytes,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
# In your webhook handler:
signature = request.headers.get("X-Zenoo-Signature")
is_valid = verify_signature(request.body, signature, WEBHOOK_SECRET)
Next steps