> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gu1.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Rule Webhook Events

> Receive real-time notifications when compliance rules are triggered — with gu1 webhook events for real-time downstream integration.

## Overview

Rule webhook events allow you to receive real-time notifications when compliance or business rules are triggered for entities in the Gu1 platform. These events enable you to automate compliance actions, alert your team, and maintain audit trails when risk conditions are detected.

## Why Use Rule Events?

<CardGroup cols={2}>
  <Card title="Real-Time Compliance" icon="gavel">
    Get instant alerts when risk rules are triggered
  </Card>

  <Card title="Automated Actions" icon="robot">
    Automatically block, flag, or escalate entities
  </Card>

  <Card title="Audit Trail" icon="clipboard-list">
    Track all rule triggers for compliance reporting
  </Card>

  <Card title="Risk Management" icon="shield-halved">
    Respond to high-risk conditions immediately
  </Card>
</CardGroup>

## Available Events

### rule.triggered

The `rule.triggered` event is fired when a compliance or business rule evaluates to true for an entity.

**When it fires**:

* A rule condition is met during entity creation or update
* Periodic rule evaluation detects a match
* Transaction monitoring rules identify suspicious activity
* Compliance checks (PEP, sanctions, adverse media) return positive matches

**Filters available**:

* `ruleIds`: Only receive events for specific rules
* `ruleSeverity`: Filter by severity level (low, medium, high, critical)
* `entityTypes`: Filter by entity type

## Event Payload

### rule.triggered Payload

```json theme={null}
{
  "event": "rule.triggered",
  "timestamp": "2025-01-07T14:00:00.000Z",
  "payload": {
    "ruleId": "550e8400-e29b-41d4-a716-446655440000",
    "rule": {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "High Risk Country Check",
      "description": "Flags entities from high-risk countries",
      "severity": "high",
      "category": "geographic_risk",
      "isActive": true
    },
    "entityId": "123e4567-e89b-12d3-a456-426614174000",
    "entity": {
      "id": "123e4567-e89b-12d3-a456-426614174000",
      "externalId": "customer_xyz789",
      "name": "John Doe",
      "type": "person",
      "countryCode": "KP",
      "status": "blocked"
    },
    "evaluationId": "eval_abc123",
    "triggerData": {
      "countryCode": "KP",
      "riskLevel": "critical",
      "matchedCriteria": [
        "sanctioned_country",
        "high_risk_jurisdiction"
      ],
      "additionalInfo": {
        "sanctionList": ["OFAC", "UN"],
        "riskScore": 95
      }
    },
    "action": {
      "type": "block",
      "reason": "Entity from sanctioned country",
      "automaticAction": true,
      "previousStatus": "under_review",
      "newStatus": "blocked"
    },
    "triggeredAt": "2025-01-07T14:00:00.000Z"
  }
}
```

### Key Payload Fields

<ResponseField name="ruleId" type="string">
  Unique identifier of the triggered rule
</ResponseField>

<ResponseField name="rule" type="object">
  Complete rule information including name, description, severity, and category
</ResponseField>

<ResponseField name="rule.severity" type="string">
  Severity level: `low`, `medium`, `high`, or `critical`
</ResponseField>

<ResponseField name="entityId" type="string">
  The entity that triggered the rule
</ResponseField>

<ResponseField name="entity" type="object">
  Complete entity information including your `externalId`
</ResponseField>

<ResponseField name="evaluationId" type="string">
  Unique identifier for this rule evaluation
</ResponseField>

<ResponseField name="triggerData" type="object">
  Data that caused the rule to trigger, including matched criteria and risk scores
</ResponseField>

<ResponseField name="action" type="object">
  Action taken as a result of the rule trigger (optional)
</ResponseField>

<ResponseField name="action.type" type="string">
  Action type: `block`, `flag`, `review`, `alert`, or `none`
</ResponseField>

<ResponseField name="action.automaticAction" type="boolean">
  Whether the action was taken automatically by Gu1
</ResponseField>

## Rule Categories and Examples

### Geographic Risk Rules

Triggered when entities are from high-risk countries or jurisdictions:

```json theme={null}
{
  "rule": {
    "name": "Sanctioned Country Check",
    "category": "geographic_risk",
    "severity": "critical"
  },
  "triggerData": {
    "countryCode": "IR",
    "sanctionList": ["OFAC", "EU"],
    "riskLevel": "critical"
  },
  "action": {
    "type": "block",
    "automaticAction": true
  }
}
```

### PEP (Politically Exposed Person) Rules

Triggered when entity matches PEP databases:

```json theme={null}
{
  "rule": {
    "name": "PEP Screening",
    "category": "pep_check",
    "severity": "high"
  },
  "triggerData": {
    "pepStatus": "confirmed",
    "position": "Former Government Official",
    "country": "XX",
    "matchConfidence": 0.95,
    "source": "World-Check"
  },
  "action": {
    "type": "review",
    "automaticAction": true
  }
}
```

### Sanctions Screening Rules

Triggered when entity appears on sanctions lists:

```json theme={null}
{
  "rule": {
    "name": "OFAC Sanctions Screening",
    "category": "sanctions",
    "severity": "critical"
  },
  "triggerData": {
    "matchType": "exact",
    "sanctionList": "OFAC SDN",
    "matchedName": "John Doe",
    "listingDate": "2020-01-15",
    "program": "Counter Terrorism"
  },
  "action": {
    "type": "block",
    "automaticAction": true
  }
}
```

### Transaction Monitoring Rules

Triggered by suspicious transaction patterns:

```json theme={null}
{
  "rule": {
    "name": "High Velocity Transactions",
    "category": "transaction_monitoring",
    "severity": "medium"
  },
  "triggerData": {
    "transactionCount": 15,
    "totalAmount": 150000,
    "timeWindow": "24h",
    "averageAmount": 10000,
    "threshold": 10
  },
  "action": {
    "type": "flag",
    "automaticAction": true
  }
}
```

### Adverse Media Rules

Triggered when negative news is found:

```json theme={null}
{
  "rule": {
    "name": "Adverse Media Screening",
    "category": "adverse_media",
    "severity": "high"
  },
  "triggerData": {
    "matchCount": 3,
    "categories": ["fraud", "financial crime"],
    "sources": ["Reuters", "Financial Times"],
    "latestDate": "2024-12-15",
    "relevanceScore": 0.85
  },
  "action": {
    "type": "review",
    "automaticAction": true
  }
}
```

## Filter Configuration

### Filter by Rule ID

Only receive events for specific rules:

```json theme={null}
{
  "eventTypes": ["rule.triggered"],
  "filters": {
    "ruleIds": [
      "rule_sanctions_ofac",
      "rule_high_risk_country"
    ]
  }
}
```

### Filter by Severity

Only receive high and critical severity alerts:

```json theme={null}
{
  "eventTypes": ["rule.triggered"],
  "filters": {
    "ruleSeverity": ["high", "critical"]
  }
}
```

### Filter by Entity Type

Only receive rules triggered for persons:

```json theme={null}
{
  "eventTypes": ["rule.triggered"],
  "filters": {
    "entityTypes": ["person"]
  }
}
```

### Combined Filters

Combine multiple filters for precise control:

```json theme={null}
{
  "eventTypes": ["rule.triggered"],
  "filters": {
    "entityTypes": ["person"],
    "ruleSeverity": ["critical"],
    "ruleIds": ["rule_sanctions_ofac", "rule_pep_screening"]
  }
}
```

## Code Examples

### Node.js - Handling Rule Events

```javascript theme={null}
const express = require('express');
const app = express();

app.use(express.json({
  verify: (req, res, buf) => {
    req.rawBody = buf.toString('utf8');
  }
}));

app.post('/webhooks/rules', async (req, res) => {
  try {
    // Verify signature (see security guide)
    if (!verifySignature(req.rawBody, req.headers['x-webhook-signature'])) {
      return res.status(401).json({ error: 'Invalid signature' });
    }

    const { event, payload } = req.body;

    if (event === 'rule.triggered') {
      await handleRuleTriggered(payload);
    }

    res.status(200).json({ success: true });
  } catch (error) {
    console.error('Webhook error:', error);
    res.status(500).json({ error: error.message });
  }
});

async function handleRuleTriggered(payload) {
  const { rule, entity, triggerData, action, evaluationId } = payload;

  console.log(`Rule triggered: ${rule.name} for ${entity.name}`);

  // Log rule trigger
  await db.ruleTriggers.create({
    data: {
      ruleId: rule.id,
      ruleName: rule.name,
      entityId: entity.id,
      externalId: entity.externalId,
      severity: rule.severity,
      triggerData,
      evaluationId,
      triggeredAt: new Date()
    }
  });

  // Handle based on severity
  switch (rule.severity) {
    case 'critical':
      await handleCriticalRule(rule, entity, triggerData, action);
      break;

    case 'high':
      await handleHighSeverityRule(rule, entity, triggerData, action);
      break;

    case 'medium':
      await handleMediumSeverityRule(rule, entity, triggerData, action);
      break;

    case 'low':
      await handleLowSeverityRule(rule, entity, triggerData, action);
      break;
  }

  // Handle based on action type
  if (action) {
    switch (action.type) {
      case 'block':
        await handleBlockAction(entity, action);
        break;

      case 'review':
        await handleReviewAction(entity, rule, action);
        break;

      case 'flag':
        await handleFlagAction(entity, rule, action);
        break;

      case 'alert':
        await handleAlertAction(entity, rule, action);
        break;
    }
  }
}

async function handleCriticalRule(rule, entity, triggerData, action) {
  console.log(`🚨 CRITICAL: ${rule.name} triggered for ${entity.name}`);

  // Immediately block entity if not already blocked
  if (entity.status !== 'blocked') {
    await blockEntity(entity.id, rule.name);
  }

  // Alert compliance team immediately
  await slack.send({
    channel: '#compliance-critical',
    priority: 'critical',
    message: `🚨 CRITICAL RULE TRIGGERED`,
    fields: {
      'Rule': rule.name,
      'Entity': entity.name,
      'External ID': entity.externalId,
      'Severity': rule.severity,
      'Action Taken': action?.type || 'none',
      'Details': JSON.stringify(triggerData, null, 2)
    }
  });

  // Create high-priority case
  await compliance.createCase({
    entityId: entity.id,
    ruleId: rule.id,
    priority: 'critical',
    type: 'rule_trigger',
    data: { rule, entity, triggerData, action },
    assignTo: 'compliance-lead'
  });

  // Send to external monitoring system
  await monitoring.alert({
    level: 'critical',
    title: `Rule Triggered: ${rule.name}`,
    entity: entity.externalId,
    rule: rule.name,
    data: triggerData
  });
}

async function handleHighSeverityRule(rule, entity, triggerData, action) {
  console.log(`⚠️ HIGH: ${rule.name} triggered for ${entity.name}`);

  // Flag entity for review
  await flagEntity(entity.id, rule.name, 'high');

  // Alert compliance team
  await slack.send({
    channel: '#compliance-alerts',
    message: `⚠️ High severity rule triggered: ${rule.name}`,
    fields: {
      'Entity': entity.name,
      'External ID': entity.externalId,
      'Rule': rule.name,
      'Action': action?.type || 'none'
    }
  });

  // Create case for review
  await compliance.createCase({
    entityId: entity.id,
    ruleId: rule.id,
    priority: 'high',
    type: 'rule_trigger',
    data: { rule, entity, triggerData }
  });
}

async function handleBlockAction(entity, action) {
  console.log(`Blocking entity: ${entity.name}`);

  // Update local database
  await db.entities.update({
    where: { gu1Id: entity.id },
    data: {
      status: 'blocked',
      blockedAt: new Date(),
      blockReason: action.reason
    }
  });

  // Disable user access
  await auth.disableUser(entity.externalId);

  // Notify entity (if required by regulations)
  await email.send({
    to: entity.attributes?.email,
    subject: 'Account Status Update',
    template: 'account-blocked',
    data: {
      name: entity.name,
      reason: action.reason,
      supportUrl: 'https://support.example.com'
    }
  });
}

async function handleReviewAction(entity, rule, action) {
  console.log(`Flagging for review: ${entity.name}`);

  // Create review task
  await tasks.create({
    type: 'compliance_review',
    entityId: entity.id,
    priority: rule.severity === 'high' ? 'high' : 'normal',
    title: `Review: ${rule.name} triggered`,
    description: action.reason,
    assignedTo: 'compliance-team',
    dueDate: new Date(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
  });
}

app.listen(3000);
```

### Python - Handling Rule Events

```python theme={null}
from flask import Flask, request, jsonify
import logging

app = Flask(__name__)

@app.route('/webhooks/rules', methods=['POST'])
def rules_webhook():
    try:
        # Verify signature (see security guide)
        signature = request.headers.get('X-Webhook-Signature')
        raw_body = request.get_data(as_text=True)

        if not verify_signature(raw_body, signature):
            return jsonify({'error': 'Invalid signature'}), 401

        # Parse webhook
        payload = request.json
        event = payload['event']
        data = payload['payload']

        if event == 'rule.triggered':
            handle_rule_triggered(data)

        return jsonify({'success': True}), 200

    except Exception as e:
        logging.error(f'Webhook error: {e}')
        return jsonify({'error': str(e)}), 500

def handle_rule_triggered(data):
    rule = data['rule']
    entity = data['entity']
    trigger_data = data['triggerData']
    action = data.get('action')

    logging.info(f"Rule triggered: {rule['name']} for {entity['name']}")

    # Log trigger
    db.rule_triggers.insert({
        'rule_id': rule['id'],
        'rule_name': rule['name'],
        'entity_id': entity['id'],
        'external_id': entity['externalId'],
        'severity': rule['severity'],
        'trigger_data': trigger_data,
        'evaluation_id': data['evaluationId']
    })

    # Handle based on severity
    severity_handlers = {
        'critical': handle_critical_rule,
        'high': handle_high_severity_rule,
        'medium': handle_medium_severity_rule,
        'low': handle_low_severity_rule
    }

    handler = severity_handlers.get(rule['severity'])
    if handler:
        handler(rule, entity, trigger_data, action)

    # Handle action
    if action:
        action_handlers = {
            'block': handle_block_action,
            'review': handle_review_action,
            'flag': handle_flag_action,
            'alert': handle_alert_action
        }

        action_handler = action_handlers.get(action['type'])
        if action_handler:
            action_handler(entity, rule, action)

def handle_critical_rule(rule, entity, trigger_data, action):
    logging.critical(f"CRITICAL: {rule['name']} triggered for {entity['name']}")

    # Block entity
    if entity['status'] != 'blocked':
        block_entity(entity['id'], rule['name'])

    # Alert team
    slack.send({
        'channel': '#compliance-critical',
        'message': f"🚨 CRITICAL RULE TRIGGERED: {rule['name']}",
        'fields': {
            'Entity': entity['name'],
            'External ID': entity['externalId'],
            'Severity': rule['severity']
        }
    })

    # Create case
    compliance.create_case({
        'entity_id': entity['id'],
        'rule_id': rule['id'],
        'priority': 'critical',
        'type': 'rule_trigger'
    })

def handle_block_action(entity, rule, action):
    logging.info(f"Blocking entity: {entity['name']}")

    # Update database
    db.entities.update(
        {'gu1_id': entity['id']},
        {
            'status': 'blocked',
            'block_reason': action['reason']
        }
    )

    # Disable access
    auth.disable_user(entity['externalId'])

if __name__ == '__main__':
    app.run(port=3000)
```

## Use Cases

### Use Case 1: Automated Compliance Actions

Automatically block high-risk entities:

```javascript theme={null}
async function handleRuleTriggered(payload) {
  const { rule, entity, action } = payload;

  if (rule.severity === 'critical' && action?.type === 'block') {
    // Immediately block all services
    await services.blockAll(entity.externalId);

    // Freeze accounts
    await accounts.freezeAll(entity.externalId);

    // Log for audit
    await audit.log({
      action: 'auto_block',
      entityId: entity.id,
      reason: action.reason,
      ruleId: rule.id,
      timestamp: new Date()
    });

    // Alert compliance team
    await notifyCompliance('critical', entity, rule);
  }
}
```

### Use Case 2: Risk Scoring and Monitoring

Update entity risk scores based on rule triggers:

```javascript theme={null}
async function updateRiskScore(entity, rule, triggerData) {
  const currentScore = await getRiskScore(entity.id);

  // Add points based on severity
  const severityPoints = {
    low: 10,
    medium: 25,
    high: 50,
    critical: 100
  };

  const newScore = currentScore + severityPoints[rule.severity];

  await db.entities.update({
    where: { gu1Id: entity.id },
    data: {
      riskScore: newScore,
      riskLevel: calculateRiskLevel(newScore),
      lastRiskUpdate: new Date()
    }
  });

  // Trigger additional reviews if score exceeds threshold
  if (newScore > 75) {
    await createEnhancedDueDiligence(entity.id);
  }
}
```

### Use Case 3: Regulatory Reporting

Generate reports for regulatory compliance:

```javascript theme={null}
async function generateComplianceReport(entity, rule, triggerData) {
  // Create SAR (Suspicious Activity Report) if required
  if (rule.category === 'transaction_monitoring' && rule.severity === 'high') {
    await reports.createSAR({
      entityId: entity.id,
      entityName: entity.name,
      ruleTriggered: rule.name,
      suspiciousActivity: triggerData,
      filedBy: 'system',
      filedAt: new Date(),
      status: 'pending_review'
    });

    // Notify compliance officer
    await notifyComplianceOfficer({
      type: 'SAR_created',
      entity,
      rule,
      data: triggerData
    });
  }
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Store Rule Triggers for Audit">
    Always log rule triggers for compliance audit trails:

    ```javascript theme={null}
    await db.ruleTriggers.create({
      data: {
        ruleId: rule.id,
        entityId: entity.id,
        evaluationId: evaluationId,
        triggerData,
        triggeredAt: new Date(),
        webhook: req.body
      }
    });
    ```
  </Accordion>

  <Accordion title="Handle Severity Appropriately">
    Implement different workflows based on severity:

    * **Critical**: Immediate blocking + urgent alerts
    * **High**: Flag for review + notify compliance team
    * **Medium**: Queue for periodic review
    * **Low**: Log only + aggregate reports
  </Accordion>

  <Accordion title="Implement Idempotency">
    Use evaluation ID to prevent duplicate processing:

    ```javascript theme={null}
    const processed = await db.webhookLog.findUnique({
      where: { evaluationId: payload.evaluationId }
    });

    if (processed) {
      return; // Skip duplicate
    }
    ```
  </Accordion>

  <Accordion title="Alert the Right Teams">
    Route alerts based on rule category:

    ```javascript theme={null}
    const alertChannels = {
      sanctions: '#compliance-sanctions',
      pep_check: '#compliance-pep',
      transaction_monitoring: '#aml-team',
      adverse_media: '#risk-team',
      geographic_risk: '#compliance-alerts'
    };

    const channel = alertChannels[rule.category] || '#compliance-general';
    await slack.send({ channel, message: alertMessage });
    ```
  </Accordion>

  <Accordion title="Track False Positives">
    Allow marking false positives for rule tuning:

    ```javascript theme={null}
    async function markFalsePositive(evaluationId, reason) {
      await db.ruleTriggers.update({
        where: { evaluationId },
        data: {
          falsePositive: true,
          falsePositiveReason: reason,
          reviewedBy: userId,
          reviewedAt: new Date()
        }
      });

      // Feed back to rule engine for optimization
      await rulesEngine.reportFalsePositive(evaluationId, reason);
    }
    ```
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Not Receiving rule.triggered Events">
    **Check**:

    * Webhook is subscribed to `rule.triggered` event
    * Rules are active in Gu1 dashboard
    * Filters match the rule properties
    * Entity type matches your filters

    **Test**:
    Create a test entity that should trigger a rule and verify the webhook fires.
  </Accordion>

  <Accordion title="Missing triggerData Fields">
    The `triggerData` structure varies by rule type and category. Not all fields will be present for all rules.

    **Example**: A geographic risk rule won't have `pepStatus`, while a PEP rule won't have `sanctionList`.
  </Accordion>

  <Accordion title="Action is null">
    The `action` field is optional. Some rules may only trigger alerts without automatic actions:

    ```javascript theme={null}
    if (payload.action) {
      await handleAction(payload.action);
    } else {
      // Rule triggered but no automatic action
      await logRuleTrigger(payload);
    }
    ```
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Entity Events" icon="user" href="/en/webhooks/events/entity-events">
    Handle entity lifecycle events
  </Card>

  <Card title="KYC Events" icon="id-card" href="/en/webhooks/events/kyc-events">
    Process KYC verification events
  </Card>

  <Card title="Webhook Security" icon="shield" href="/en/webhooks/security">
    Secure your webhook endpoints
  </Card>

  <Card title="Configuration" icon="gear" href="/en/webhooks/configuration">
    Configure webhook settings
  </Card>
</CardGroup>
