# Guide: Building Your Own Detection Rules

This section walks you through creating custom detection rules. Use the system rules above as templates and reference examples.

#### The Five Building Blocks

Every detection rule has five components that work together:

```
┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   SOURCE    │ →  │   FILTER    │ →  │  AGGREGATE  │ →  │  EVALUATE   │ →  │ FINGERPRINT │
│             │    │             │    │             │    │             │    │             │
│ What data   │    │ Which       │    │ How to      │    │ When to     │    │ How to      │
│ to query    │    │ records     │    │ summarize   │    │ trigger     │    │ identify    │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
```

***

#### Step 1: Choose Your Data Source

The source tells the rule what type of data to query from your connected system.

**Available Sources by Integration:**

| Integration    | Available Objects                                                   |
| -------------- | ------------------------------------------------------------------- |
| **Zuora**      | account, subscription, invoice, payment, billrun, creditmemo, usage |
| **Stripe**     | customer, invoice, payment\_intent, subscription, refund, dispute   |
| **Salesforce** | Account, Opportunity, Lead, Contact, Case                           |

**Example from System Rules:**

* *Failed Bill Run Detection* uses `billrun` from Zuora
* *Dispute Rate Signal* uses `dispute` from Stripe
* *Stale Opportunity Pipeline* uses `Opportunity` from Salesforce

***

#### Step 2: Add Filters

Filters narrow down which records to examine. You can combine multiple filters.

**Available Operators:**

| Operator | Meaning               | Example                                    |
| -------- | --------------------- | ------------------------------------------ |
| `=`      | Equals                | Status equals "Error"                      |
| `!=`     | Not equals            | Status is not "Active"                     |
| `>`      | Greater than          | Amount greater than 1000                   |
| `>=`     | Greater than or equal | Balance at least 0                         |
| `<`      | Less than             | Count less than 5                          |
| `<=`     | Less than or equal    | Age at most 30 days                        |
| `in`     | Matches any in list   | Status is "Error", "Failed", or "Canceled" |
| `not_in` | Doesn't match any     | Stage is not "Closed Won" or "Closed Lost" |

**Examples from System Rules:**

| Rule                        | Filter Logic                                                                      |
| --------------------------- | --------------------------------------------------------------------------------- |
| Failed Bill Run Detection   | Status **in** \["Error", "Failed", "Canceled"]                                    |
| Outstanding Account Balance | Balance **>** 0 **AND** Status **=** "Active"                                     |
| High-Value Deal at Risk     | Amount **>** 100,000 **AND** IsClosed **=** false                                 |
| Stale Opportunity Pipeline  | IsClosed **=** false **AND** StageName **not\_in** \["Closed Won", "Closed Lost"] |

**Tip:** Use multiple filters to be precise. The *Outstanding Account Balance* rule uses two filters to find only active accounts with a positive balance—this avoids false signals from closed accounts.

***

#### Step 3: Configure Aggregation

Aggregation determines how the rule summarizes the filtered data.

**Aggregation Functions:**

| Function | What It Does                 | Use When                                               |
| -------- | ---------------------------- | ------------------------------------------------------ |
| `count`  | Counts the number of records | You care about **how many** (e.g., failed payments)    |
| `sum`    | Adds up a numeric field      | You care about **total amount** (e.g., refund dollars) |

**Time Windows:**

| Window        | Duration | Best For                |
| ------------- | -------- | ----------------------- |
| 60 minutes    | 1 hour   | Detecting sudden spikes |
| 360 minutes   | 6 hours  | Short-term patterns     |
| 1440 minutes  | 24 hours | Daily monitoring        |
| 10080 minutes | 7 days   | Weekly trends           |

**Grouping Options:**

| Approach             | Result                          | Use When                                            |
| -------------------- | ------------------------------- | --------------------------------------------------- |
| No grouping          | One total for all records       | You want overall volume (e.g., total refund amount) |
| Group by account     | Separate count/sum per account  | You want per-customer signals                       |
| Group by owner       | Separate count/sum per owner    | You want per-rep signals                            |
| Group by status/type | Separate count/sum per category | You want to see patterns by type                    |

**Examples from System Rules:**

| Rule                    | Function     | Window   | Grouped By          |
| ----------------------- | ------------ | -------- | ------------------- |
| Failed Payment Spike    | count        | 1 hour   | Payment method type |
| Credit Memo Spike       | sum (amount) | 24 hours | Not grouped         |
| Subscription Churn Risk | count        | 7 days   | Account             |
| Lead Response Time SLA  | count        | 24 hours | Lead owner          |

**Tip:** The *Failed Payment Spike* rule uses a short 1-hour window and groups by payment method type—this helps you spot if a specific payment processor is having issues.

***

#### Step 4: Set the Evaluation Threshold

The threshold determines when the rule creates a signal.

**Available Comparisons:**

| Operator      | Meaning               | Example      |
| ------------- | --------------------- | ------------ |
| `>` or `gt`   | Greater than          | More than 10 |
| `>=` or `gte` | Greater than or equal | 1 or more    |
| `<` or `lt`   | Less than             | Fewer than 5 |
| `<=` or `lte` | Less than or equal    | 100 or fewer |
| `=` or `eq`   | Equals                | Exactly 0    |

**Choosing the Right Threshold:**

| Scenario                     | Recommended Threshold                               |
| ---------------------------- | --------------------------------------------------- |
| Any occurrence is a problem  | >= 1 (e.g., failed bill runs)                       |
| Small numbers are normal     | > 5 or > 10 (e.g., payment declines)                |
| Large volumes are concerning | > 10,000 (e.g., usage spikes)                       |
| Dollar amounts               | Set based on your business (e.g., > $5,000 refunds) |

**Examples from System Rules:**

| Rule                      | Threshold       | Reasoning                                         |
| ------------------------- | --------------- | ------------------------------------------------- |
| Failed Bill Run Detection | >= 1            | Any failed bill run needs attention               |
| Failed Payment Spike      | > 10 per hour   | A few failures are normal; 10+ suggests a problem |
| High Invoice Aging        | > 5 per account | Multiple aged invoices indicate collection issues |
| Large Refund Volume       | > $5,000/day    | High refund volume may signal problems            |

**Tip:** Start with a higher threshold to reduce noise, then lower it as you understand your normal patterns.

***

#### Step 5: Configure Fingerprinting

Fingerprinting controls how signals are grouped and deduplicated.

**Fingerprint Modes:**

| Mode        | Behavior                           | Use When                                                       |
| ----------- | ---------------------------------- | -------------------------------------------------------------- |
| `entity`    | One signal per unique record       | You want to track individual items (e.g., each failed payment) |
| `aggregate` | One signal for the overall pattern | You want to track volume trends (e.g., daily refund total)     |

**Examples from System Rules:**

| Rule                    | Mode      | Fields                 | Result                                  |
| ----------------------- | --------- | ---------------------- | --------------------------------------- |
| Failed Payment Signal   | entity    | Account ID, Payment ID | One signal per failed payment           |
| Credit Memo Spike       | aggregate | (none)                 | One signal when daily total is high     |
| Subscription Churn Risk | entity    | Account ID             | One signal per at-risk account          |
| Failed Payment Spike    | aggregate | Payment method type    | One signal per payment type with issues |

**Tip:** Use `entity` mode when each individual record needs attention. Use `aggregate` mode when you care about overall patterns rather than individual items.

***

#### Putting It All Together: A Custom Rule Example

Let's say you want to detect **Zuora accounts with failed payments in the last week that have a balance over $500**.

**Step 1 - Source:** Zuora accounts

**Step 2 - Filters:**

* Balance > 500
* Status = "Active"

**Step 3 - Aggregation:**

* Function: count
* Window: 7 days (10080 minutes)
* Group by: Account ID

**Step 4 - Evaluation:**

* Threshold: >= 1 (any matching account)

**Step 5 - Fingerprint:**

* Mode: entity
* Fields: Account ID

**Result:** You'll get one signal for each active account with a balance over $500, and the signals won't duplicate for the same account within the week.

***

#### Quick Reference: Common Rule Patterns

**Pattern 1: Catch Every Occurrence**

{% code overflow="wrap" lineNumbers="true" %}

```
Use when: Each individual issue needs attention
Filter: Specific error condition
Aggregate: count, no grouping
Threshold: >= 1
Fingerprint: entity mode with record ID
Example: Failed Bill Run Detection
```

{% endcode %}

**Pattern 2: Detect Volume Spikes**

{% code overflow="wrap" lineNumbers="true" %}

```
Use when: High volume indicates a systemic issue
Filter: Broad or no filter
Aggregate: count or sum, short time window (1-6 hours)
Threshold: High number based on your normal volume
Fingerprint: aggregate mode
Example: Failed Payment Spike, Credit Memo Spike
```

{% endcode %}

**Pattern 3: Per-Customer Monitoring**

{% code overflow="wrap" lineNumbers="true" %}

```
Use when: You want signals grouped by customer/account
Filter: Problem condition
Aggregate: count, group by account/customer ID
Threshold: >= 1 or based on acceptable count
Fingerprint: entity mode with account ID
Example: Outstanding Account Balance, Failed Subscription Payment
```

{% endcode %}

**Pattern 4: Team Performance Tracking**

{% code overflow="wrap" lineNumbers="true" %}

```
Use when: Monitoring by owner/rep
Filter: Condition indicating issues
Aggregate: count, group by owner ID
Threshold: Based on acceptable workload
Fingerprint: entity mode with owner ID
Example: Lead Response Time SLA, Stale Opportunity Pipeline
```

{% endcode %}

***

### Rule Categories Explained

| Category             | What It Covers                                      |
| -------------------- | --------------------------------------------------- |
| **Payment Health**   | Payment processing, failures, gateway issues        |
| **Billing Accuracy** | Invoice generation, bill runs, pricing errors       |
| **Revenue Leakage**  | Unbilled usage, missed charges, lost revenue        |
| **Churn Risk**       | Cancellations, at-risk customers, retention signals |
| **Pipeline Health**  | Sales opportunity progress and stale deals          |
| **Sales Efficiency** | Lead response times and sales process metrics       |
| **Revenue Risk**     | High-value deals at risk of loss                    |
| **Data Integrity**   | Data quality, sync issues, missing records          |

***

### Severity Levels

| Level        | When to Use                                | Response Time       |
| ------------ | ------------------------------------------ | ------------------- |
| **Critical** | Immediate revenue or customer impact       | Same day            |
| **Warning**  | Potential issue that needs attention       | Within a few days   |
| **Info**     | Awareness item, no immediate action needed | Review periodically |

***

### Best Practices

1. **Start with Critical Rules** - Activate the critical severity rules first as they catch the most urgent issues
2. **Link to Production Integrations** - Connect rules to your production systems, not test environments
3. **Monitor the System Feed** - Check your feed regularly for new signals from detection rules
4. **Document Your Responses** - Use the signal notes feature to track what actions you've taken
5. **Review Rule Performance** - Periodically check if rules are generating useful signals or need adjustment
