# RevCent MCP Operation: `CreateCustomerGroup`

This document explains the `CreateCustomerGroup` operation in depth so MCP clients can correctly create Customer Groups in RevCent.

This is not a general overview. It is an operation-specific implementation guide focused on fields, nested properties, qualifier logic, validation rules, examples, and common mistakes.

Source:
- RevCent API/MCP schema for `CreateCustomerGroup`

---

## Operation Summary

`CreateCustomerGroup` creates a new Customer Group and returns a unique 20-character `customer_group_id`.

A Customer Group can be:

1. A manual group where customers are added/removed directly.
2. A rule-based group where customers qualify based on customer values, filters, metadata, and subscription behavior.
3. A composite group where customers qualify based on membership or non-membership in other Customer Groups.

Customer Groups can be used for:

- Customer segmentation
- Reporting
- Filtering
- Revenue recovery
- AI Assistant triggers
- AI Voice Agent targeting
- Email workflows
- Support prioritization
- Risk review
- Subscription lifecycle workflows
- Third-party automation

---

## Important Schema Behavior

The input schema has:

```json
"additionalProperties": false
```

MCP clients must not send unknown fields.

Only send fields defined by the schema:

```text
name
description
enabled
qualifier_method
qualifiers
```

Although the schema does not mark every top-level field as required, MCP should not create vague or unusable Customer Groups. A well-formed Customer Group should almost always include:

```text
name
description
enabled
qualifier_method
qualifiers, when qualifier_method requires qualifiers
```

---

# Top-Level Fields

| Field | Type | Required by Schema | Recommended | Description |
|---|---:|---:|---:|---|
| `name` | string | No | Yes | Customer Group name. Should be clear and unique. |
| `description` | string | No | Yes | Explains the group purpose, qualifiers, and intended workflows. |
| `enabled` | boolean | No | Yes | Whether the group is enabled. |
| `qualifier_method` | string enum | No | Yes | Determines how customers qualify for the group. |
| `qualifiers` | object | No | Depends | Qualifier object. Shape depends on `qualifier_method`. |

---

## `name`

The Customer Group name should clearly describe the segment.

Good names:

```text
VIP Customers
High Value Payment Recovery
Winback Candidates
Trial Conversion
Overdue Renewal Recovery
Affiliate 123 Buyers
Manual Risk Review
Do Not Contact
Subscription Save
```

Poor names:

```text
Group 1
Test
Customers
List
Recovery
```

MCP should avoid vague names because Customer Groups may later trigger automation. A vague name can cause the wrong AI Assistant, AI Voice Agent, Function, or external tool to act on the wrong customer segment.

---

## `description`

The description is strongly recommended.

The description should explain:

- What the group means.
- How customers qualify.
- Whether customers are added manually or by qualifiers.
- Whether the group is used for reporting, filtering, or automation.
- Whether group added/removed events should trigger workflows.
- Whether the group is safe for customer outreach.
- Any suppression or human-review rules.

Good description:

```text
Customers with lifetime value >= 500 and at least one overdue renewal. Used for high-value subscription payment recovery. customer.updated.customer_group.added may trigger an AI Assistant review and AI Voice Agent recovery workflow.
```

Manual group description:

```text
Manual group for customers who should not receive automated outreach. Customers are added or removed by support, AI review, or external workflow. No automatic qualifiers.
```

---

## `enabled`

`enabled` controls whether the Customer Group is enabled.

Recommended default:

```json
"enabled": false
```

while drafting, testing, or reviewing complex qualifiers.

Use:

```json
"enabled": true
```

when the group is ready for production use.

For groups that trigger automation, MCP should be cautious about enabling the group immediately. A misconfigured group may add or remove many customers and trigger downstream workflows.

---

## `qualifier_method`

`qualifier_method` determines how customers qualify.

Allowed values:

```text
specific_values
customer_group
none
```

| Value | Meaning | Active Qualifier Branch |
|---|---|---|
| `none` | Manual/workflow-only group. No automatic qualifiers are evaluated. | None. All qualifiers are ignored. |
| `specific_values` | Customers qualify based on values, filters, metadata, and/or subscription options. | Only `qualifiers.specific_values`. |
| `customer_group` | Customers qualify based on membership or non-membership in other Customer Groups. | Only `qualifiers.customer_group`. |

MCP should always choose `qualifier_method` intentionally.

---

---

# Critical Concept: `qualifier_method` Controls Which Qualifiers Matter

`qualifier_method` is the controlling switch for how the Customer Group determines membership.

MCP clients must understand that the three qualifier methods are mutually exclusive in how qualification logic is interpreted.

The selected `qualifier_method` determines which part of the `qualifiers` object matters.

| `qualifier_method` | Meaning | What Is Used | What Is Ignored |
|---|---|---|---|
| `none` | Manual/workflow-only group. | No qualifiers are used. Customers must be added or removed manually or by workflow. | All qualifiers, filters, specific values, subscription options, and customer-group rules are ignored. |
| `customer_group` | Group membership-based qualification. | Only `qualifiers.customer_group` is used. | `qualifiers.specific_values`, including filters, values, metadata, and subscription options, are ignored. |
| `specific_values` | Rule-based qualification from customer data. | Only `qualifiers.specific_values` is used, including filters, values, metadata, and subscription options. | `qualifiers.customer_group` is ignored. |

Rule:

```text
qualifier_method decides which qualifier branch is active.
```

Do not assume all objects inside `qualifiers` are evaluated.

They are not.

---

## `none` Means Manual Only

When:

```json
"qualifier_method": "none"
```

the Customer Group has no automatic qualification criteria.

Customers do not qualify based on:

- Campaign filters
- Product group filters
- Third-party shop filters
- Metadata filters
- Lifetime value
- Sales count
- Refund amount
- Chargeback count
- Fraud detections
- Subscription status
- Renewal count
- Other Customer Groups

All qualifier logic is ignored.

This group is manual only, meaning customers must be added or removed through:

- Manual action
- A workflow
- A Function
- An AI Assistant action
- An AI Voice Agent workflow
- An external integration
- Another automation process

Use `none` for groups like:

```text
Do Not Contact
Manual Risk Review
Needs Human Support
Approved For Special Offer
Escalated Support
AI Classified Customer
```

Recommended request shape:

```json
{
  "name": "Manual Risk Review",
  "description": "Manual/workflow-only group. Customers are added or removed by support, AI review, Function, or external workflow. No qualifiers are evaluated.",
  "enabled": true,
  "qualifier_method": "none",
  "qualifiers": {}
}
```

Important:

Even if an MCP accidentally includes `qualifiers.specific_values` or `qualifiers.customer_group`, those qualifier rules should not be treated as active when `qualifier_method` is `none`.

Best practice:

```text
When qualifier_method = none, send qualifiers as an empty object.
```

---

## `customer_group` Means Membership in Other Groups Only

When:

```json
"qualifier_method": "customer_group"
```

the Customer Group qualifies customers based only on their relationship to other Customer Groups.

Only this branch matters:

```json
"qualifiers": {
  "customer_group": {
    "in_any_customer_group": [],
    "in_all_customer_group": [],
    "not_in_customer_group": []
  }
}
```

This method does not evaluate:

- Campaign filters
- Product group filters
- Third-party shop filters
- Metadata filters
- Lifetime value
- Sales count
- Refund amount
- Chargeback count
- Fraud detections
- Subscription status
- Renewal count
- Subscription options

Those all belong to `specific_values` and are ignored when `qualifier_method` is `customer_group`.

Use `customer_group` when the user wants a composite group based on other groups.

Examples:

```text
Customer is in VIP
Customer is in High LTV and Winback Candidate
Customer is in Payment Recovery but not Do Not Contact
Customer is in Trial User or Trial Expired
Customer is not in Manual Review
```

Recommended request shape:

```json
{
  "name": "High Value Winback Eligible",
  "description": "Composite group based only on membership in other Customer Groups. Customer must be in High Value and Winback Candidate, and must not be in Do Not Contact.",
  "enabled": false,
  "qualifier_method": "customer_group",
  "qualifiers": {
    "customer_group": {
      "in_any_customer_group": [],
      "in_all_customer_group": [
        "HIGH_VALUE_GROUP_ID",
        "WINBACK_GROUP_ID"
      ],
      "not_in_customer_group": [
        "DO_NOT_CONTACT_GROUP_ID"
      ]
    }
  }
}
```

Important:

When `qualifier_method = customer_group`, do not include `specific_values` logic expecting it to apply.

This would be wrong:

```json
{
  "qualifier_method": "customer_group",
  "qualifiers": {
    "customer_group": {
      "in_all_customer_group": [
        "HIGH_VALUE_GROUP_ID"
      ]
    },
    "specific_values": {
      "values": {
        "lifetime_value": {
          "enabled": true,
          "min": 500,
          "max": 999999
        }
      }
    }
  }
}
```

The `lifetime_value` qualifier belongs to `specific_values`; it should not be expected to qualify customers when the method is `customer_group`.

Best practice:

```text
When qualifier_method = customer_group, only send qualifiers.customer_group.
```

---

## `specific_values` Means Filters, Values, Metadata, and Subscription Options

When:

```json
"qualifier_method": "specific_values"
```

the Customer Group qualifies customers based on customer data rules.

Only this branch matters:

```json
"qualifiers": {
  "specific_values": {
    "filters": {},
    "values": {},
    "subscription_options": {}
  }
}
```

This is the only method where the following are evaluated:

- Campaign filters
- Product group filters
- Third-party shop filters
- Metadata filters
- Lifetime value
- Lifetime refunded amount
- Sales count
- Average sale amount
- Days since last sale
- Successful sale count
- Upsell sale count
- Declined sale count
- Abandoned sale count
- Fraud detection count
- Chargeback amount
- Chargeback count
- PayPal dispute amount
- PayPal dispute count
- Subscription renewal behavior
- Subscription status

This method ignores `qualifiers.customer_group`.

Use `specific_values` when the user wants a group based on the customer’s own data or behavior.

Examples:

```text
Customers with lifetime value >= 500
Customers with at least 1 declined sale
Customers from campaign X
Customers with metadata affiliate_id = aff_123
Customers with subscription status = overdue
Customers with no sales after 7 days
Customers who purchased Product Group A
```

Recommended request shape:

```json
{
  "name": "High Value Payment Recovery",
  "description": "Customers with lifetime value of at least 500 and at least one declined sale. Uses specific customer values for payment recovery segmentation.",
  "enabled": false,
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {
        "campaign": [],
        "product_group": [],
        "third_party_shop": [],
        "metadata": []
      },
      "values": {
        "has_no_sales": false,
        "lifetime_value": {
          "enabled": true,
          "min": 500,
          "max": 999999
        },
        "num_pending_declined_sale": {
          "enabled": true,
          "min": 1,
          "max": 999999
        }
      },
      "subscription_options": {
        "enabled": false,
        "status": []
      }
    }
  }
}
```

Important:

When `qualifier_method = specific_values`, do not include `customer_group` logic expecting it to apply.

This would be wrong:

```json
{
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "values": {
        "lifetime_value": {
          "enabled": true,
          "min": 500,
          "max": 999999
        }
      }
    },
    "customer_group": {
      "not_in_customer_group": [
        "DO_NOT_CONTACT_GROUP_ID"
      ]
    }
  }
}
```

The `not_in_customer_group` qualifier belongs to the `customer_group` method; it should not be expected to qualify customers when the method is `specific_values`.

If the user needs both specific-value logic and customer-group inclusion/exclusion logic, create separate groups and then create a composite `customer_group` group.

Best practice:

```text
When qualifier_method = specific_values, only send qualifiers.specific_values.
```

---

## How to Combine Specific Values and Customer Group Membership

Because `specific_values` and `customer_group` are separate methods, MCP clients should not try to combine both branches in one group.

If the business needs logic like:

```text
Lifetime value >= 500
AND customer is not in Do Not Contact
```

do not create one group with:

```text
qualifier_method = specific_values
+ qualifiers.customer_group.not_in_customer_group
```

Instead, use a layered group strategy.

Recommended approach:

### Step 1: Create Specific-Value Group

```text
High Value Customers
= lifetime_value >= 500
```

Use:

```text
qualifier_method = specific_values
```

### Step 2: Create Composite Group

```text
High Value Outreach Eligible
= in High Value Customers
AND not in Do Not Contact
```

Use:

```text
qualifier_method = customer_group
```

This keeps qualification logic clear and avoids relying on ignored branches.

---

## Decision Guide

Use this decision guide before creating a Customer Group.

| User Intent | Correct `qualifier_method` |
|---|---|
| “I want to manually add customers to this group.” | `none` |
| “AI or support will add customers to this group.” | `none` |
| “External CRM will decide who belongs in this group.” | `none` |
| “Group customers who are already in another group.” | `customer_group` |
| “Group customers who are in A and B, but not C.” | `customer_group` |
| “Group customers by lifetime value.” | `specific_values` |
| “Group customers by metadata.” | `specific_values` |
| “Group customers by campaign.” | `specific_values` |
| “Group customers by product group purchased.” | `specific_values` |
| “Group customers by subscription status.” | `specific_values` |
| “Group customers by declined sales or abandoned sales.” | `specific_values`, or layered groups if complex OR logic is needed |
| “Group customers by customer data and also exclude Do Not Contact.” | Create a `specific_values` group, then a composite `customer_group` group |

---

## Common Qualifier Method Mistakes

### Mistake 1: Sending Filters With `none`

Wrong expectation:

```text
qualifier_method = none
but filters should still qualify customers
```

Correct understanding:

```text
none ignores all qualifiers. It is manual/workflow-only.
```

---

### Mistake 2: Sending Specific Values With `customer_group`

Wrong expectation:

```text
qualifier_method = customer_group
but lifetime_value should also apply
```

Correct understanding:

```text
customer_group only evaluates qualifiers.customer_group.
```

---

### Mistake 3: Sending Customer Group Exclusions With `specific_values`

Wrong expectation:

```text
qualifier_method = specific_values
but not_in_customer_group should also apply
```

Correct understanding:

```text
specific_values only evaluates qualifiers.specific_values.
```

---

### Mistake 4: Trying to Build Every Rule Into One Group

Wrong approach:

```text
One Customer Group with specific values, metadata, subscription rules, and group membership rules all mixed together.
```

Correct approach:

```text
Use one qualifier method per group. Build layered groups when needed.
```

---

## MCP Rule

```text
Never rely on an inactive qualifier branch.
```

If `qualifier_method` is:

```text
none
```

then no qualifier branch is active.

If `qualifier_method` is:

```text
customer_group
```

then only `qualifiers.customer_group` is active.

If `qualifier_method` is:

```text
specific_values
```

then only `qualifiers.specific_values` is active.


# `qualifier_method: "none"`

Use `none` when the group should not automatically qualify customers.

This means the group has no qualification criteria.

Customers must be added or removed manually or by workflow.

Example request:

```json
{
  "name": "Manual Risk Review",
  "description": "Manual group for customers requiring risk review. Customers are added by support, AI review, or external workflows. No automatic qualifiers.",
  "enabled": true,
  "qualifier_method": "none",
  "qualifiers": {}
}
```

Use cases:

- Manual VIP review
- Do Not Contact
- Escalated Support
- Manual Risk Review
- Approved For Special Offer
- Human Follow-Up Needed
- AI Classified Segment
- External CRM Segment

Important:

If `qualifier_method` is `none`, MCP must treat the group as manual/workflow-only. `qualifiers.specific_values`, `qualifiers.filters`, `qualifiers.values`, `qualifiers.subscription_options`, and `qualifiers.customer_group` are ignored.

---

# `qualifier_method: "specific_values"`

Use `specific_values` when customers should qualify based only on customer behavior, filters, metadata, or subscription options. In this mode, customer-group membership qualifiers are ignored.

Expected shape:

```json
{
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {},
      "values": {},
      "subscription_options": {}
    }
  }
}
```

The `specific_values` object can include:

| Property | Purpose |
|---|---|
| `filters` | Campaign, product group, third-party shop, and metadata filters. |
| `values` | Numeric or value-based customer qualifiers such as lifetime value, sales count, refunds, chargebacks, etc. |
| `subscription_options` | Subscription-related qualifiers such as renewal count, overdue renewals, and subscription status. |

---

# `specific_values.filters`

Filters qualify customers based on related objects or metadata.

Shape:

```json
"filters": {
  "campaign": [],
  "product_group": [],
  "third_party_shop": [],
  "metadata": []
}
```

---

## `filters.campaign`

Type:

```text
array<string>
```

Each value must be a 20-character campaign ID.

Meaning:

Customers qualify if they are associated with one of the listed campaigns.

If empty:

```json
"campaign": []
```

there is no campaign filter.

If multiple campaign IDs are provided, a customer only needs to match one of them.

Logic:

```text
campaign A OR campaign B OR campaign C
```

Example:

```json
"campaign": [
  "XXXXXXXXXXXXXXXXXXXX",
  "YYYYYYYYYYYYYYYYYYYY"
]
```

Use cases:

- Customers from a specific campaign
- Affiliate campaign segmentation
- Paid traffic analysis
- Campaign-specific recovery workflow

---

## `filters.product_group`

Type:

```text
array<string>
```

Each value must be a 20-character product group ID.

Meaning:

Customers qualify if they have purchased a product within one of the listed product groups.

If empty, there is no product group qualification.

If multiple product group IDs are provided, a customer only needs to match one of them.

Logic:

```text
product_group A OR product_group B OR product_group C
```

Use cases:

- Reorder campaigns
- Product-specific support
- Cross-sell segmentation
- Customers who bought subscription products
- Customers who bought high-ticket products

Example:

```json
"product_group": [
  "XXXXXXXXXXXXXXXXXXXX"
]
```

---

## `filters.third_party_shop`

Type:

```text
array<string>
```

Each value must be a 20-character user shop ID.

Meaning:

Customers qualify if they made a purchase from one of the listed third-party shops.

If empty, there is no third-party shop qualification.

If multiple shop IDs are provided, a customer only needs to match one of them.

Logic:

```text
shop A OR shop B OR shop C
```

Use cases:

- Segment customers by WooCommerce/Shopify/shop source
- Separate brand/store reporting
- Channel-specific engagement
- Store-specific support workflow

Example:

```json
"third_party_shop": [
  "XXXXXXXXXXXXXXXXXXXX"
]
```

---

## `filters.metadata`

Type:

```text
array<object>
```

Each metadata filter object has:

| Field | Type | Description |
|---|---:|---|
| `name` | string | Metadata name to qualify on. |
| `value` | string | Metadata value, or `METADATA_NAME_EXISTS`. |

Example:

```json
"metadata": [
  {
    "name": "affiliate_id",
    "value": "aff_123"
  }
]
```

Meaning:

Customer must have metadata:

```text
affiliate_id = aff_123
```

Special value:

```text
METADATA_NAME_EXISTS
```

Example:

```json
"metadata": [
  {
    "name": "crm_id",
    "value": "METADATA_NAME_EXISTS"
  }
]
```

Meaning:

Customer qualifies if metadata name `crm_id` exists, regardless of value.

---

## Metadata Filter Logic

Metadata filters are stricter than campaign/product/shop filters.

If multiple metadata filters are provided, the customer must qualify for all metadata filters.

General logic:

```text
metadata filter 1 AND metadata filter 2 AND metadata filter 3
```

However, if multiple values are provided for the same metadata name, values are grouped by name and the customer must match at least one value for that name.

Example:

```json
"metadata": [
  {
    "name": "affiliate_id",
    "value": "aff_123"
  },
  {
    "name": "affiliate_id",
    "value": "aff_456"
  },
  {
    "name": "customer_tier",
    "value": "gold"
  }
]
```

Logic:

```text
(affiliate_id = aff_123 OR affiliate_id = aff_456)
AND customer_tier = gold
```

MCP must understand this grouping behavior.

---

# `specific_values.values`

`values` contains customer metrics and numeric qualifiers.

General behavior:

- A customer must match all enabled specific values.
- If a value is not enabled, it does not affect qualification.
- If enabled, the customer must be greater than or equal to `min`.
- If enabled, the customer must be less than or equal to `max`.
- If enabled and both `min` and `max` are `0`, then the corresponding customer value must be exactly `0`.

General shape:

```json
"lifetime_value": {
  "enabled": true,
  "min": 500,
  "max": 999999
}
```

General logic:

```text
customer.lifetime_value >= min
AND customer.lifetime_value <= max
```

MCP should only enable values that the user explicitly wants to qualify on.

---

## Important Range Rule

For most value objects:

```json
{
  "enabled": true,
  "min": 0,
  "max": 0
}
```

means:

```text
Customer value must be exactly 0
```

This is not the same as “no max.”

If the user means no practical upper limit, MCP should use a large enough max according to the schema/business need, not `0`.

---

## `values.has_no_sales`

Type:

```text
boolean
```

Meaning:

If `true`, customer must have 0 sales on record.

Important schema behavior:

If `has_no_sales` is `true`, then no other `qualifiers.specific_values.values` are considered except `days_since_created`.

This means the following are ignored when `has_no_sales` is true:

- `lifetime_value`
- `lifetime_refunded`
- `num_sale`
- `avg_sale`
- `days_last_sale`
- `num_success_sale`
- `num_upsell_sale`
- `num_pending_declined_sale`
- `num_pending_abandoned_sale`
- `num_fraud_detection`
- `lifetime_chargeback`
- `num_chargeback`
- `lifetime_paypal_dispute`
- `num_paypal_dispute`

Recommended default:

```json
"has_no_sales": false
```

Use cases:

- Prospects
- Signups with no purchase attempts
- Leads created before checkout
- Customers who have not attempted any purchases

Example:

```json
"values": {
  "has_no_sales": true,
  "days_since_created": {
    "enabled": true,
    "min": 7,
    "max": 365
  }
}
```

Meaning:

```text
Customer has 0 sales
AND customer was created between 7 and 365 days ago
```

---

## `values.days_since_created`

Type:

```text
object
```

Fields:

| Field | Type | Notes |
|---|---:|---|
| `enabled` | boolean | Whether this qualifier is active. |
| `min` | integer | Minimum days since creation. Must be greater than 0. |
| `max` | integer | Maximum days since creation. Must be greater than 0. |

Use cases:

- New customers
- Old leads
- Prospects created more than N days ago
- Customers created in a specific age window

Example:

```json
"days_since_created": {
  "enabled": true,
  "min": 7,
  "max": 30
}
```

Meaning:

```text
Customer was created 7 to 30 days ago
```

---

## `values.lifetime_value`

Type:

```text
object
```

Fields:

```text
enabled, min, max
```

Uses customer lifetime value.

Use cases:

- VIP customers
- High-value recovery
- Customer success prioritization
- Offer eligibility
- Reporting segments

Example:

```json
"lifetime_value": {
  "enabled": true,
  "min": 500,
  "max": 999999
}
```

Meaning:

```text
Lifetime value is at least 500
```

---

## `values.lifetime_refunded`

Uses lifetime sum amount of refunds.

Use cases:

- High refund risk
- Refund review
- Customer quality analysis
- Support escalation

Example:

```json
"lifetime_refunded": {
  "enabled": true,
  "min": 100,
  "max": 999999
}
```

---

## `values.num_sale`

Uses total sales count.

Use cases:

- First-time buyers
- Repeat buyers
- Customers with no purchases
- Customers with many purchases

Example:

```json
"num_sale": {
  "enabled": true,
  "min": 2,
  "max": 999999
}
```

Meaning:

```text
Customer has at least 2 sales
```

---

## `values.avg_sale`

Uses average sale amount.

Use cases:

- High average order value customers
- Low AOV customers
- Premium buyer segments

Example:

```json
"avg_sale": {
  "enabled": true,
  "min": 100,
  "max": 999999
}
```

---

## `values.days_last_sale`

Uses days since last sale.

Fields:

| Field | Type | Notes |
|---|---:|---|
| `enabled` | boolean | Whether active. |
| `min` | integer | Minimum days since last sale. Must be greater than 0. |
| `max` | integer | Maximum days since last sale. Must be greater than 0. |

Use cases:

- Winback candidates
- Dormant customers
- Recently active customers
- Reorder timing

Example:

```json
"days_last_sale": {
  "enabled": true,
  "min": 90,
  "max": 365
}
```

Meaning:

```text
Customer has not purchased for 90 to 365 days
```

---

## `values.num_success_sale`

Uses number of successful sales.

Use cases:

- Customers who completed purchases
- Repeat successful buyers
- Customers who attempted but never successfully purchased

Example:

```json
"num_success_sale": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_upsell_sale`

Uses number of upsell sales.

Use cases:

- Customers who accept upsells
- Upsell-responsive customers
- Funnel optimization

Example:

```json
"num_upsell_sale": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_pending_declined_sale`

Uses number of declined sales.

Use cases:

- Decline recovery
- Payment update outreach
- Failed sale recovery
- High-value payment salvage

Example:

```json
"num_pending_declined_sale": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_pending_abandoned_sale`

Uses number of abandoned sales.

Use cases:

- Abandoned cart/sale recovery
- High-intent customer recovery
- Email reminder workflows
- AI Voice Agent follow-up

Example:

```json
"num_pending_abandoned_sale": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_fraud_detection`

Uses fraud detection count.

Use cases:

- Fraud review
- Risk workflows
- Manual review queues
- Suppression from automated outreach

Example:

```json
"num_fraud_detection": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.lifetime_chargeback`

Uses lifetime sum amount of chargebacks.

Use cases:

- Chargeback risk
- Risk review
- Customer quality analysis

Example:

```json
"lifetime_chargeback": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_chargeback`

Uses number of chargebacks.

Use cases:

- Chargeback review
- Fraud/risk segmentation
- Manual support handling

Example:

```json
"num_chargeback": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.lifetime_paypal_dispute`

Uses lifetime sum amount of PayPal disputes.

Use cases:

- PayPal dispute risk
- Payment method risk analysis
- Support escalation

Example:

```json
"lifetime_paypal_dispute": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

## `values.num_paypal_dispute`

Uses number of PayPal disputes.

Use cases:

- PayPal dispute review
- Risk segmentation
- Manual review

Example:

```json
"num_paypal_dispute": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

---

# `specific_values.subscription_options`

Subscription options qualify customers based on subscription behavior.

Shape:

```json
"subscription_options": {
  "enabled": true,
  "days_last_renewal": {},
  "num_renewal": {},
  "num_success_renewal": {},
  "num_overdue_renewal": {},
  "status": []
}
```

Important:

If `subscription_options.enabled` is not true, subscription options should not be treated as active qualification criteria.

---

## `subscription_options.enabled`

Type:

```text
boolean
```

Meaning:

Whether subscription options are active.

Use:

```json
"enabled": true
```

only when the group should qualify customers based on subscription-related conditions.

---

## `subscription_options.days_last_renewal`

Fields:

```text
enabled, min, max
```

Uses days since the customer’s last subscription renewal.

Example:

```json
"days_last_renewal": {
  "enabled": true,
  "min": 30,
  "max": 90
}
```

Use cases:

- Recently renewed customers
- Customers due for follow-up after renewal
- Renewal lifecycle segments

---

## `subscription_options.num_renewal`

Uses number of subscription renewals completed.

Example:

```json
"num_renewal": {
  "enabled": true,
  "min": 3,
  "max": 999999
}
```

Use cases:

- Long-term subscribers
- Subscription loyalty groups
- Retention segments

---

## `subscription_options.num_success_renewal`

Uses number of successful subscription renewals.

Example:

```json
"num_success_renewal": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

Use cases:

- Reliable subscribers
- Customers who have successfully renewed
- Subscription quality segments

---

## `subscription_options.num_overdue_renewal`

Uses number of overdue subscription renewals.

Example:

```json
"num_overdue_renewal": {
  "enabled": true,
  "min": 1,
  "max": 999999
}
```

Use cases:

- Subscription payment recovery
- Overdue renewal outreach
- AI Voice Agent recovery calls
- High-value subscription save workflows

---

## `subscription_options.status`

Type:

```text
array<string>
```

Allowed statuses:

```text
active
trial
overdue
occurrence_limit
suspended
cancelled
```

If empty:

```json
"status": []
```

there is no subscription status qualification.

If multiple statuses are provided, a customer only needs to match one of them.

Logic:

```text
status active OR status trial OR status overdue
```

Example:

```json
"status": [
  "trial",
  "overdue"
]
```

Use cases:

- Trial customers
- Overdue subscription customers
- Cancelled subscription winback
- Active subscriber segments
- Suspended subscriber review

---

# `qualifier_method: "customer_group"`

Use `customer_group` when customers should qualify based only on their membership or non-membership in other Customer Groups. In this mode, specific value qualifiers, filters, metadata, and subscription options are ignored.

Expected shape:

```json
{
  "qualifier_method": "customer_group",
  "qualifiers": {
    "customer_group": {
      "in_any_customer_group": [],
      "in_all_customer_group": [],
      "not_in_customer_group": []
    }
  }
}
```

---

## `customer_group.in_any_customer_group`

Type:

```text
array<string>
```

Each value must be a 20-character Customer Group ID.

Meaning:

Customer must be in at least one of the selected groups.

Logic:

```text
Group A OR Group B OR Group C
```

Example:

```json
"in_any_customer_group": [
  "XXXXXXXXXXXXXXXXXXXX",
  "YYYYYYYYYYYYYYYYYYYY"
]
```

---

## `customer_group.in_all_customer_group`

Type:

```text
array<string>
```

Each value must be a 20-character Customer Group ID.

Meaning:

Customer must be in all selected groups.

Logic:

```text
Group A AND Group B AND Group C
```

Example:

```json
"in_all_customer_group": [
  "XXXXXXXXXXXXXXXXXXXX",
  "YYYYYYYYYYYYYYYYYYYY"
]
```

---

## `customer_group.not_in_customer_group`

Type:

```text
array<string>
```

Each value must be a 20-character Customer Group ID.

Meaning:

Customer must not be in at least one selected group.

The schema description says this represents customer groups that customers must not be in to qualify.

Use cases:

- Suppress Do Not Contact
- Exclude Manual Review
- Exclude Fraud Review
- Exclude already recovered customers
- Exclude existing VIP customers

Example:

```json
"not_in_customer_group": [
  "XXXXXXXXXXXXXXXXXXXX"
]
```

---

# Composite Group Example

Example:

```text
High Value Winback Eligible
```

Meaning:

```text
Customer must be in High Value group
AND customer must be in Winback Candidate group
AND customer must not be in Do Not Contact group
```

Request concept:

```json
{
  "name": "High Value Winback Eligible",
  "description": "Composite group for high value customers who are winback candidates and are not suppressed from outreach.",
  "enabled": true,
  "qualifier_method": "customer_group",
  "qualifiers": {
    "customer_group": {
      "in_any_customer_group": [],
      "in_all_customer_group": [
        "HIGH_VALUE_GROUP_ID",
        "WINBACK_GROUP_ID"
      ],
      "not_in_customer_group": [
        "DO_NOT_CONTACT_GROUP_ID"
      ]
    }
  }
}
```

Replace placeholder IDs with real 20-character Customer Group IDs.

---

# Full Example: Manual Group

```json
{
  "name": "Do Not Contact",
  "description": "Manual suppression group. Customers in this group should be excluded from automated outreach workflows.",
  "enabled": true,
  "qualifier_method": "none",
  "qualifiers": {}
}
```

---

# Full Example: VIP Customers

```json
{
  "name": "VIP Customers",
  "description": "Customers with lifetime value of at least 1000, no chargebacks, and at least 2 successful sales. Used for priority support and VIP engagement.",
  "enabled": false,
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {
        "campaign": [],
        "product_group": [],
        "third_party_shop": [],
        "metadata": []
      },
      "values": {
        "has_no_sales": false,
        "lifetime_value": {
          "enabled": true,
          "min": 1000,
          "max": 999999
        },
        "num_success_sale": {
          "enabled": true,
          "min": 2,
          "max": 999999
        },
        "num_chargeback": {
          "enabled": true,
          "min": 0,
          "max": 0
        }
      },
      "subscription_options": {
        "enabled": false,
        "status": []
      }
    }
  }
}
```

Important:

`num_chargeback` with min `0` and max `0` means the customer must have exactly zero chargebacks.

---

# Full Example: Winback Candidates

```json
{
  "name": "Winback Candidates",
  "description": "Customers with lifetime value of at least 250 who have not purchased in 90 to 365 days. Used for winback email, AI Assistant offer selection, and optional AI Voice Agent follow-up.",
  "enabled": false,
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {
        "campaign": [],
        "product_group": [],
        "third_party_shop": [],
        "metadata": []
      },
      "values": {
        "has_no_sales": false,
        "lifetime_value": {
          "enabled": true,
          "min": 250,
          "max": 999999
        },
        "days_last_sale": {
          "enabled": true,
          "min": 90,
          "max": 365
        }
      },
      "subscription_options": {
        "enabled": false,
        "status": []
      }
    }
  }
}
```

---

# Full Example: Affiliate Segment

```json
{
  "name": "Affiliate 123 Buyers",
  "description": "Customers with metadata affiliate_id = aff_123 and at least one successful sale. Used for affiliate reporting and customer quality analysis.",
  "enabled": true,
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {
        "campaign": [],
        "product_group": [],
        "third_party_shop": [],
        "metadata": [
          {
            "name": "affiliate_id",
            "value": "aff_123"
          }
        ]
      },
      "values": {
        "has_no_sales": false,
        "num_success_sale": {
          "enabled": true,
          "min": 1,
          "max": 999999
        }
      },
      "subscription_options": {
        "enabled": false,
        "status": []
      }
    }
  }
}
```

---

# Full Example: Payment Recovery Group

```json
{
  "name": "Payment Recovery",
  "description": "Customers with at least one declined sale or overdue renewal. Used for decline salvage, payment update email, AI Assistant recovery analysis, and AI Voice Agent outreach.",
  "enabled": false,
  "qualifier_method": "specific_values",
  "qualifiers": {
    "specific_values": {
      "filters": {
        "campaign": [],
        "product_group": [],
        "third_party_shop": [],
        "metadata": []
      },
      "values": {
        "has_no_sales": false,
        "num_pending_declined_sale": {
          "enabled": true,
          "min": 1,
          "max": 999999
        }
      },
      "subscription_options": {
        "enabled": true,
        "num_overdue_renewal": {
          "enabled": true,
          "min": 1,
          "max": 999999
        },
        "status": [
          "overdue"
        ]
      }
    }
  }
}
```

Note:

This example may be interpreted as requiring both the enabled declined-sale qualifier and subscription qualifier depending on platform qualification behavior. If the business intent is “declined sale OR overdue renewal,” it may be safer to create separate groups and combine them with `qualifier_method: "customer_group"` using `in_any_customer_group`.

---

# OR vs AND Logic Guidance

MCP must be careful with qualification logic.

## OR-Like Behavior

These arrays are OR-style within their category:

```text
campaign
product_group
third_party_shop
subscription_options.status
customer_group.in_any_customer_group
```

Examples:

```text
campaign A OR campaign B
```

```text
status trial OR overdue
```

---

## AND-Like Behavior

These are generally AND-style:

```text
multiple enabled specific_values.values
multiple metadata names
in_all_customer_group
filters combined with values/subscription options
```

Examples:

```text
lifetime_value >= 500
AND days_last_sale >= 90
```

```text
affiliate_id = aff_123
AND customer_tier = gold
```

---

## Mixed Metadata Behavior

Multiple values for the same metadata name are grouped OR-style, while different metadata names are AND-style.

Example:

```text
(affiliate_id = aff_123 OR affiliate_id = aff_456)
AND customer_tier = gold
```

---

# Handling “OR” Requirements

If the user wants a broad OR across unrelated qualifier types, MCP should avoid forcing it into a single `specific_values` group unless the schema clearly supports that exact logic.

Example user intent:

```text
Customers with at least one declined sale OR at least one overdue renewal.
```

Safer design:

1. Create group `Declined Sale Customers`.
2. Create group `Overdue Renewal Customers`.
3. Create group `Payment Recovery` using `qualifier_method: "customer_group"` with both groups in `in_any_customer_group`.

This avoids accidentally creating an AND condition.

---

# Customer Group Events

Creating a Customer Group may later cause group membership changes.

Important event notations:

```text
customer.updated.customer_group.added
customer.updated.customer_group.removed
```

These events can trigger automation when customers enter or leave a group.

Examples:

- AI Assistant runs when customer enters `High Value Recovery`.
- AI Voice Agent calls when customer enters `Payment Recovery`.
- Function updates CRM when customer enters `VIP`.
- External AI Agent reviews risk when customer enters `Fraud Review`.
- Email Template sends winback message when customer enters `Winback Candidates`.

MCP should document in the group description if group events are intended to trigger automation.

---

# MCP Questions Before Creating a Customer Group

Before calling `CreateCustomerGroup`, MCP should ask:

1. What should the Customer Group be named?
2. What is the business purpose of the group?
3. Should the group be enabled immediately?
4. Should customers be added manually, by specific values, or by other Customer Groups?
5. If manual, who or what workflow will add/remove customers?
6. If specific values, which exact qualifiers should be enabled?
7. Are campaign filters needed?
8. Are product group filters needed?
9. Are third-party shop filters needed?
10. Are metadata filters needed?
11. Does the user mean metadata even if they did not say “metadata”?
12. Are lifetime value, sales count, refunds, chargebacks, disputes, or fraud detection qualifiers needed?
13. Are subscription qualifiers needed?
14. Does the desired logic require AND or OR?
15. Would separate groups plus a composite group be safer?
16. Should group added/removed events trigger AI Assistants, AI Voice Agents, Functions, emails, or external tools?
17. Should the group start disabled for review/testing?
18. Should the group be used for filtering, reporting, automation, or all three?

---

# Validation Checklist

Before submitting `CreateCustomerGroup`:

1. No unknown top-level fields are included.
2. `name` is clear and specific.
3. `description` explains purpose, qualifiers, and intended workflow use.
4. `enabled` is intentionally set.
5. `qualifier_method` is one of `specific_values`, `customer_group`, or `none`.
6. The selected qualifier_method has only one active qualifier branch.
7. Inactive qualifier branches are not relied on.
8. If `qualifier_method` is `none`, qualifiers do not contain unintended active logic.
9. If `qualifier_method` is `specific_values`, `qualifiers.specific_values` is present.
10. If `qualifier_method` is `customer_group`, `qualifiers.customer_group` is present.
11. All 20-character IDs are real IDs, not placeholders.
12. Empty arrays are used intentionally to mean no filter for that field.
13. Metadata filters use correct name/value pairs.
14. `METADATA_NAME_EXISTS` is used only when existence, not value match, is intended.
15. Numeric ranges are intentional.
16. No enabled range accidentally uses min `0` and max `0` unless exact zero is intended.
17. `has_no_sales` is true only when the group is meant for zero-sale customers.
18. If `has_no_sales` is true, MCP understands other value qualifiers except `days_since_created` are ignored.
19. Subscription options are enabled only when subscription qualification is intended.
20. Subscription statuses are valid enum values.
21. OR vs AND logic has been reviewed.
22. Complex OR logic is split into separate groups if needed.
23. Event-triggered automation implications are documented.
24. Group starts disabled if qualifiers or automation are high impact.
---

# Common Mistakes

## Mistake: Using `0` Max as “No Limit”

Wrong assumption:

```json
"lifetime_value": {
  "enabled": true,
  "min": 500,
  "max": 0
}
```

This may not mean “500 or higher.” Use an intentional max value.

---

## Mistake: Accidentally Requiring Exact Zero

This means exactly zero:

```json
"num_chargeback": {
  "enabled": true,
  "min": 0,
  "max": 0
}
```

Use it only when exact zero is intended.

---

## Mistake: Forgetting `has_no_sales` Overrides Other Value Qualifiers

If this is true:

```json
"has_no_sales": true
```

then other `specific_values.values` are ignored except `days_since_created`.

---

## Mistake: Treating Metadata Filters as OR Across Different Names

This:

```json
[
  { "name": "affiliate_id", "value": "aff_123" },
  { "name": "customer_tier", "value": "gold" }
]
```

means:

```text
affiliate_id = aff_123
AND customer_tier = gold
```

not OR.

---

## Mistake: Creating an Automated Group Enabled Immediately

If group added/removed events trigger workflows, enabling a group with broad qualifiers can immediately trigger many workflows.

For high-impact groups, create disabled first.

---

# Output Schema

Successful response:

```json
{
  "api_call_id": "XXXXXXXXXXXXXXXXXXXX",
  "api_call_unix": 1740000000,
  "code": 1,
  "customer_group_id": "XXXXXXXXXXXXXXXXXXXX",
  "result": "..."
}
```

| Field | Description |
|---|---|
| `api_call_id` | 20-character API call ID. |
| `api_call_unix` | Unix timestamp when the call was initiated. |
| `code` | API response code. `1` indicates success. |
| `customer_group_id` | 20-character Customer Group ID created by the operation. |
| `result` | Human-readable result message. |

---

# Quick Reference

Top-level shape:

```json
{
  "name": "Customer Group Name",
  "description": "What this group means and how it is used.",
  "enabled": false,
  "qualifier_method": "specific_values",
  "qualifiers": {}
}
```

Qualifier methods:

```text
none = manual/workflow-only membership; all qualifiers ignored
specific_values = only qualifiers.specific_values is active; filters, values, metadata, subscription options
customer_group = only qualifiers.customer_group is active; membership/non-membership in other groups
```

Most important MCP rule:

```text
Customer Groups can trigger real customer workflows. Build qualifiers carefully, understand AND/OR behavior, and create disabled first when automation or broad qualification could affect many customers.
```


---
Document Parent Directory
* [Operations](https://revcent.com/documentation/markdown/mcp/operation/index.md) - AI/MCP details and overviews for operations available within the RevCent MCP.