Skip to main content

Defining Products and CGRateS Configuration

This guide explains how to define products in OmniCRM along with their associated CGRateS billing configuration.

Products and their CGRateS Actions are typically defined together in Python scripts that configure both the CRM and OCS (Online Charging System).

Overview

Defining a complete product involves configuration in two systems:

  1. CGRateS/OCS - Define the billing behavior (Actions, Rates, Destinations)
  2. OmniCRM - Define the product metadata (price, name, features)

These are intentionally loosely linked, allowing you to interact with CGrateS via the Ansible Plays you define.

Important: CGRateS Capabilities

CGRateS is an extremely powerful and flexible rating engine. This guide shows one common configuration pattern for OmniCRM products, but CGRateS can do much more:

  • Advanced rating scenarios: Time-of-day rates, customer tiers, call quality-based routing, burst billing
  • Complex roaming logic: Different rates for MO vs MT calls/SMS when roaming, network-specific pricing
  • Legacy protocol support: CAMEL for 2G/3G roaming (MO-MT SMS, USSD), Diameter for LTE/5G
  • Sophisticated charging: Reservation-based charging, credit control, multi-tier fallback
  • Dynamic routing: Cost-based routing, supplier selection, LCR (Least Cost Routing)

This is just the CRM guide - it focuses on simple product definition patterns that work well with OmniCRM's provisioning system. For advanced CGRateS configurations, consult the CGRateS documentation or see CGRateS Actions and Topup Behaviors for balance approaches and rating strategies.

Complete Product Definition Workflow

Step 1: Authenticate to CRM API

import requests
import json

crm_url = 'https://crm.example.com/'
session = requests.Session()

headers = {
"Content-Type": "application/json"
}

# Get authentication token
response = session.post(crm_url + '/crm/auth/login', json={
"email": "admin@example.com",
"password": "your_password"
}, headers=headers)

assert response.status_code == 200
headers['Authorization'] = 'Bearer ' + response.json()['token']
print("Auth to CRM OK")

Step 2: Define Inventory Templates (Optional)

Inventory templates define the types of physical items (SIM cards, routers, etc.) that can be assigned during provisioning.

inventory_list_new = []

# Define SIM Card inventory template
inventory_list_new.append({
"item": "SIM Card",
"itemtext1_label": "ICCID",
"itemtext2_label": "IMSI",
"wholesale_cost": 0.2,
"retail_cost": 1,
"allow_dropdown_staff": True,
"allow_dropdown_customer": True,
"icon": "fa-solid fa-sim-card"
})

# Define Mobile Number inventory template
inventory_list_new.append({
"item": "Mobile Number",
"itemtext1_label": "E.164 Mobile Number",
"itemtext2_label": "Type",
"wholesale_cost": 0.2,
"retail_cost": 3,
"icon": "fa-solid fa-phone"
})

# Check if inventory template exists, create or update
for inventory_template in inventory_list_new:
# Get existing templates
inventory_list_existing = session.get(
crm_url + '/crm/inventory/item_template/',
headers=headers
)

# Check if template already exists
if inventory_template['item'] in [x['item'] for x in inventory_list_existing.json()]:
# Update existing template
inventory_template_id = [
x['inventory_template_id']
for x in inventory_list_existing.json()
if x['item'] == inventory_template['item']
][0]

response = session.patch(
crm_url + '/crm/inventory/item_template/' + str(inventory_template_id),
json=inventory_template,
headers=headers
)
assert response.status_code == 200
print(f"Updated inventory template: {inventory_template['item']}")
else:
# Create new template
response = session.put(
crm_url + '/crm/inventory/item_template',
json=inventory_template,
headers=headers
)
assert response.status_code == 200
print(f"Created inventory template: {inventory_template['item']}")

Inventory Template Fields:

  • item (required) - Template name
  • itemtext1_label - Label for first custom field
  • itemtext2_label - Label for second custom field
  • wholesale_cost - Your cost for this item
  • retail_cost - Customer-facing cost
  • allow_dropdown_staff - Show in staff dropdowns
  • allow_dropdown_customer - Show in customer dropdowns
  • icon - Font Awesome icon class

Step 3: Connect to CGRateS

import cgrateshttpapi
import time

OCS_Obj = cgrateshttpapi.CGRateS("ocs.example.com", "2080")

tenant = "your_tenant_name"
tpid = str(tenant) + "_" + str(int(time.time()))

Step 4: Define Destinations in CGRateS

Destinations define WHERE balances can be used. They must be defined before creating Actions that reference them.

There are two types:

  1. Geographic Destinations - Number prefixes for voice/SMS TO specific places (e.g., Dest_AU_Mobile, Dest_International_UK)
  2. PLMN Destinations - Network codes for data usage and roaming (e.g., Dest_PLMN_OnNet, Dest_PLMN_US_Verizon)

Critical Rule:

  • Voice/SMS balances → Use geographic destinations (the number being called TO)
  • Data balances → Use PLMN destinations (the network customer is connected on FROM)

For complete destination definition examples including:

  • Geographic destinations (mobile, fixed-line, toll-free, international)
  • PLMN destinations (on-net, roaming, zones)
  • PLMN format rules (mccXXX.mncYYY)
  • When to use each approach

See: CGRateS Actions - Defining Destinations

Step 5: Define CGRateS Actions

Actions are the mechanism for adding balances to customer accounts. Before you can link a CRM product to an Action, the Action must be defined in CGRateS.

Critical: Actions are defined during initial system configuration (not during provisioning). They specify what balances to add, expiry times, rollover behavior, etc.

See CGRateS Actions and Topup Behaviors for complete documentation on:

  • How to define Actions using Python (OCS_Obj.SendData)
  • Understanding *topup vs *topup_reset (rollover behavior)
  • Unit calculations (bytes for data, nanoseconds for voice, count for SMS)
  • Field reference (BalanceId, BalanceType, DestinationIDs, Units, ExpiryTime, Weight)
  • Complete working examples (multi-balance plans, data addons, voice addons)
  • Balance consumption rules and priority

Quick Rollover Reference:

  • *topup - Adds to existing balance (enables rollover). For: prepaid addons, data packs
  • *topup_reset - Replaces existing balance (no rollover). For: monthly plans with fixed allowances

Step 6: Create Products in CRM

Now that Actions are defined in CGRateS, create the corresponding products in CRM.

Example: Standalone SIM Service

product_list_new = []

product_list_new.append({
"category": "standalone",
"provisioning_play": "play_psim_only",
"relies_on_list": "",
"contract_days": 0,
"retail_cost": 0,
"retail_setup_cost": 0,
"product_slug": "Mobile-SIM",
"product_name": "Mobile SIM Only",
"comment": "Physical SIM card for use with Mobile Phones",
"provisioning_json_vars": "{\"iccid\" : \"\", \"msisdn\" : \"\"}",
"terms": "Must be activated within 6 months. All credit lost if service is not used for 12 months.",
"service_type": "mobile",
"residential": True,
"business": True,
"enabled": True,
"inventory_items_list": "['SIM Card', 'Mobile Number']",
"icon": "fa-solid fa-sim-card",
"features_list": "['Australian Phone Number (61xxx)', 'Fastest speeds', 'Best coverage']",
"wholesale_cost": 3,
"wholesale_setup_cost": 1,
"customer_can_purchase": True
})

Example: Monthly Plan Addon

product_list_new.append({
"category": "addon",
"provisioning_play": "play_topup_charge_then_action",
"relies_on_list": "",
"contract_days": 30,
"retail_cost": 59.00,
"retail_setup_cost": 0,
"product_slug": "au-premium-plan-1", # Links to Action_au-premium-plan-1
"product_name": "AU Premium Plan 1",
"comment": "100GB Data in Australia, 3000 Minutes in Australia, 3000 SMS in Australia, 6GB Roaming Data",
"provisioning_json_vars": "",
"terms": "Postpaid plan. Auto-renews every 30 days.",
"service_type": "mobile",
"residential": True,
"business": True,
"enabled": True,
"icon": "fa-solid fa-mobile",
"features_list": "['100GB Data in Australia', '3000 Minutes in Australia', '3000 SMS in Australia', '6GB Roaming Data']",
"wholesale_cost": 45.00,
"wholesale_setup_cost": 0,
"auto_renew": "True",
"customer_can_purchase": True
})

Example: One-Time Topup Addon

product_list_new.append({
"category": "addon",
"provisioning_play": "play_topup_charge_then_action",
"relies_on_list": "",
"contract_days": 0,
"retail_cost": 30,
"retail_setup_cost": 0,
"product_slug": "au-data-addon-20gb", # Links to Action_au-data-addon-20gb
"product_name": "AU Data Addon 20GB",
"comment": "20GB Data in Australia",
"provisioning_json_vars": "",
"terms": "Prepaid top-up. Immediate charge.",
"service_type": "mobile",
"residential": True,
"business": True,
"enabled": True,
"icon": "fa-solid fa-mobile",
"features_list": "['20GB Data in Australia']",
"wholesale_cost": 22,
"wholesale_setup_cost": 0,
"auto_renew": "False",
"customer_can_purchase": True
})

Product Field Descriptions:

  • category (required) - Product category:
    • standalone - Complete service (creates new service record)
    • addon - Added to existing service
    • bundle - Package of multiple services
  • provisioning_play (required) - Ansible playbook to execute (e.g., play_topup_charge_then_action, play_simple_service)
  • relies_on_list - Comma-separated list of product_slugs this product depends on
  • contract_days - Contract duration in days (0 = no contract, 30 = monthly)
  • retail_cost (required) - Customer-facing monthly/recurring cost
  • retail_setup_cost - One-time setup fee charged to customer
  • product_slug (required) - Unique identifier that links to CGRateS Action (convention: Action_{product_slug})
  • product_name (required) - Display name
  • comment - Short description
  • provisioning_json_vars - JSON string of variables passed to playbook
  • terms - Terms and conditions text
  • service_type - Service classification (mobile, dongle, fixed, etc.)
  • residential - Available to residential customers
  • business - Available to business customers
  • enabled - Product is active and purchasable
  • inventory_items_list - Python list string of required inventory items
  • icon - Font Awesome icon class
  • features_list - Python list string of feature bullets
  • wholesale_cost - Your recurring cost
  • wholesale_setup_cost - Your one-time cost
  • auto_renew - "True" or "False" string for automatic renewal
  • customer_can_purchase - Customer can buy via self-service portal

See also: Product Lifecycle

Step 7: Create or Update Products via API

# Get existing products
product_list_existing = session.get(crm_url + '/crm/product', headers=headers)
existing_products = product_list_existing.json()

# Process each product
for product in product_list_new:
print(f"Processing product: {product['product_slug']}")

# Check if product already exists
if product['product_slug'] in [x['product_slug'] for x in existing_products]:
print(f"Product already exists: {product['product_slug']}")

# Get product_id of existing product
product_id = [
x['product_id']
for x in existing_products
if x['product_slug'] == product['product_slug']
][0]

product['product_id'] = product_id

# Update existing product
response = session.patch(
crm_url + '/crm/product/' + str(product_id),
json=product,
headers=headers
)
print(f"Status: {response.status_code}")
assert response.status_code == 200
print(f"Updated product: {product['product_slug']}")
else:
# Create new product
print(f"Creating new product: {product['product_slug']}")
response = session.put(
crm_url + '/crm/product',
json=product,
headers=headers
)
print(f"Status: {response.status_code}")
assert response.status_code == 200
print(f"Created product: {product['product_slug']}")

Linking Products to Actions

The critical link between CRM products and CGRateS Actions is the naming convention:

# In CGRateS
ActionsId = "Action_au-premium-plan-1"

# In CRM
product_slug = "au-premium-plan-1"

# In playbook (automatically constructed)
cgr_action_name = "Action_" + product_slug
# Result: "Action_au-premium-plan-1"

How Playbooks Execute Actions

Note: Using ExecuteAction is just one pattern for adding balances. You could also directly call SetBalance or other CGRateS APIs inside a playbook. However, OmniCRM-API/Provisioners/plays/play_topup_charge_then_action.yaml uses the ExecuteAction pattern as it's a common, reusable approach that separates balance logic (Actions) from provisioning logic (Playbooks).

When a product is provisioned using this pattern, the playbook constructs the Action name from the product_slug:

# In play_topup_charge_then_action.yaml
- name: Set cgr_action_name fact
set_fact:
cgr_action_name: "Action_{{ api_response_product.json.product_slug }}"

# Execute the action
- name: Execute CGRateS action
uri:
url: "http://{{ crm_config.ocs.cgrates }}/jsonrpc"
method: POST
body_format: json
body:
{
"method": "APIerSv1.ExecuteAction",
"params": [{
"Tenant": "{{ crm_config.ocs.ocsTenant }}",
"Account": "{{ service_uuid }}",
"ActionsId": "{{ cgr_action_name }}"
}]
}

When using this pattern: The Action must exist in CGRateS before the playbook runs, otherwise execution will fail with "Action not found" error.

See also: Ansible Playbooks Guide

Complete Example: Defining a New Product

Let's walk through creating a complete new product "50GB Data Pack":

1. Define the Action in CGRateS

See the Simple Data Addon example in Step 5 above for how to define a data addon Action. For our 50GB example, the Action would follow the same pattern but with different units:

  • ActionsId: "Action_50gb-data-pack" (matches product_slug below)
  • BalanceType: "*data"
  • DestinationIDs: "Dest_PLMN_OnNet" (for on-net data usage)
  • Units: 50 * 1024 * 1024 * 1024 (50GB in bytes)
  • Identifier: "*topup" (enables rollover)

2. Create the Product in CRM

product_50gb_data = {
"category": "addon",
"provisioning_play": "play_topup_charge_then_action",
"relies_on_list": "",
"contract_days": 0,
"retail_cost": 25.00,
"retail_setup_cost": 0,
"product_slug": "50gb-data-pack", # Must match ActionsId without "Action_"
"product_name": "50GB Data Pack",
"comment": "50GB of high-speed data valid for 30 days",
"provisioning_json_vars": "",
"terms": "Data expires after 30 days. Unused data rolls over if topped up again before expiry.",
"service_type": "mobile",
"residential": True,
"business": True,
"enabled": True,
"icon": "fa-solid fa-database",
"features_list": "['50GB High-Speed Data', '30 Day Validity', 'Rollover Enabled']",
"wholesale_cost": 20.00,
"wholesale_setup_cost": 0,
"auto_renew": "False",
"customer_can_purchase": True
}

# Create in CRM
response = session.put(
crm_url + '/crm/product',
json=product_50gb_data,
headers=headers
)
assert response.status_code == 200
print("Product created: 50gb-data-pack")

The product can now be provisioned:

  1. Customer purchases "50GB Data Pack" (product_slug: 50gb-data-pack)
  2. Playbook play_topup_charge_then_action executes
  3. Playbook constructs Action name: Action_50gb-data-pack
  4. Playbook calls APIerSv1.ExecuteAction with ActionsId Action_50gb-data-pack
  5. CGRateS finds the Action and executes it
  6. Customer receives 50GB balance

See also: Charging and Payments from Playbooks

Common Product Patterns

These patterns show typical CRM product configurations and how they link to CGRateS Actions. For the corresponding Action definitions, see CGRateS Actions and Topup Behaviors.

Pattern 1: Multi-Balance Monthly Plan

Use Case: Comprehensive monthly plan with data, voice, SMS, roaming

CRM Product:

{
"product_slug": "premium-monthly-plan", # Links to Action_premium-monthly-plan
"product_name": "Premium Monthly Plan",
"category": "addon",
"retail_cost": 59.00,
"auto_renew": "True",
"contract_days": 30,
"provisioning_play": "play_topup_charge_then_action",
"features_list": "['100GB Data', '5000 Minutes', '5000 SMS', 'Roaming Included']"
}

Action: Uses *topup_reset with multiple balance types. See Example 1: Multi-Balance Monthly Plan (Python).

Pattern 2: Simple Data Addon (Rollover)

Use Case: One-time data purchase that rolls over if topped up again

CRM Product:

{
"product_slug": "10gb-addon", # Links to Action_10gb-addon
"product_name": "10GB Data Addon",
"category": "addon",
"retail_cost": 15.00,
"auto_renew": "False", # One-time purchase
"contract_days": 0,
"provisioning_play": "play_topup_charge_then_action",
"features_list": "['10GB Data with Rollover', '30 Day Validity']"
}

Action: Uses *topup for rollover behavior. See CGRateS Actions - Rollover.

Pattern 3: Fixed Monthly Plan (No Rollover)

Use Case: Monthly plan that always resets to exactly the same amount

CRM Product:

{
"product_slug": "fixed-50gb-monthly", # Links to Action_fixed-50gb-monthly
"product_name": "Fixed 50GB Monthly",
"category": "addon",
"retail_cost": 35.00,
"auto_renew": "True",
"contract_days": 30,
"provisioning_play": "play_topup_charge_then_action",
"features_list": "['50GB Data', 'Resets Monthly', 'No Rollover']"
}

Action: Uses *topup_reset to prevent rollover. See CGRateS Actions - Reset Behavior.

Advanced: Chargers and Rating Plans

Important: This section covers basic pay-per-use rating. CGRateS supports incredibly sophisticated rating scenarios including:

  • Differential roaming rates: Different prices for MO vs MT calls/SMS when roaming
  • Protocol-specific charging: CAMEL for 2G/3G (MO-MT SMS, USSD), Diameter for 4G/5G
  • Context-aware pricing: Rates based on time, location, customer segment, network quality
  • Multi-dimensional rating: Combining network type, roaming status, destination, and time-of-day

The examples below show simple, flat-rate PAYG configurations suitable for most OmniCRM deployments.

For pay-as-you-go billing (where usage beyond included balances costs money), you need to define Rating Plans that specify dollar amounts to charge.

How Rating Works

When a customer uses a service (data, voice, SMS):

  1. CGRateS checks for unitary balances (e.g., included data GB)
  2. If unitary balance exists, usage is deducted from it
  3. If no unitary balance or balance exhausted, CGRateS falls back to monetary balance
  4. Rating Plan determines the price (e.g., $0.10 per MB)
  5. The calculated cost is deducted from the customer's monetary balance

Example: Setting Up Pay-Per-Use Data Charges

# 1. Define a Destination Rate (the price)
OCS_Obj.SendData({
"method": "ApierV2.SetTPDestinationRate",
"params": [{
"TPid": tpid,
"ID": "DR_DATA_PAYG",
"DestinationRates": [{
"DestinationId": "Dest_PLMN_OnNet",
"RateId": "RT_DATA_$0_10_PER_MB",
"RoundingMethod": "*up",
"RoundingDecimals": 4,
"MaxCost": 0,
"MaxCostStrategy": ""
}]
}]
})

# 2. Define the actual rate
OCS_Obj.SendData({
"method": "ApierV2.SetTPRate",
"params": [{
"TPid": tpid,
"ID": "RT_DATA_$0_10_PER_MB",
"RateSlots": [{
"ConnectFee": 0, # No connection charge
"Rate": 0.10, # $0.10 per unit
"RateUnit": "1048576", # 1 MB (1024 * 1024 bytes)
"RateIncrement": "1048576", # Bill per MB
"GroupIntervalStart": "0s"
}]
}]
})

# 3. Define a Rating Plan that uses this rate
OCS_Obj.SendData({
"method": "ApierV2.SetTPRatingPlan",
"params": [{
"TPid": tpid,
"ID": "RP_PAYG_DATA",
"RatingPlanBindings": [{
"DestinationRatesId": "DR_DATA_PAYG",
"TimingId": "*any",
"Weight": 10
}]
}]
})

# 4. Link the Rating Plan to a Rating Profile (for specific accounts)
OCS_Obj.SendData({
"method": "ApierV2.SetTPRatingProfile",
"params": [{
"TPid": tpid,
"Tenant": tenant,
"Category": "data",
"Subject": "*any", # Or specific account identifier
"RatingPlanActivations": [{
"ActivationTime": "2024-01-01T00:00:00Z",
"RatingPlanId": "RP_PAYG_DATA",
"FallbackSubjects": ""
}]
}]
})

# 5. Load the tariff plan
OCS_Obj.SendData({
"method": "APIerSv1.LoadTariffPlanFromStorDb",
"params": [{
"TPid": tpid,
"DryRun": False,
"Validate": True,
"APIOpts": {}
}]
})

What this does:

  • When a customer has no data balance (or runs out), data usage costs $0.10 per MB
  • The charge is deducted from their monetary balance (*monetary)
  • Billing increments are 1 MB (rounds up)

Example: Voice Call Rates

# Define different rates for different destinations
OCS_Obj.SendData({
"method": "ApierV2.SetTPRate",
"params": [{
"TPid": tpid,
"ID": "RT_VOICE_DOMESTIC_$0_30_PER_MIN",
"RateSlots": [{
"ConnectFee": 0.15, # $0.15 connection fee
"Rate": 0.30, # $0.30 per minute
"RateUnit": "60s", # Bill per minute
"RateIncrement": "60s", # Round to full minutes
"GroupIntervalStart": "0s"
}]
}]
})

OCS_Obj.SendData({
"method": "ApierV2.SetTPRate",
"params": [{
"TPid": tpid,
"ID": "RT_VOICE_INTL_$1_50_PER_MIN",
"RateSlots": [{
"ConnectFee": 0.25, # $0.25 connection fee
"Rate": 1.50, # $1.50 per minute
"RateUnit": "60s",
"RateIncrement": "1s", # Bill per second (more accurate)
"GroupIntervalStart": "0s"
}]
}]
})

Charger Profiles (Optional)

Chargers apply rating to specific types of events. For most use cases, the default charger is sufficient:

OCS_Obj.SendData({
"method": "APIerSv1.SetChargerProfile",
"params": [{
"Tenant": tenant,
"ID": "Charger_Default",
"FilterIDs": [],
"AttributeIDs": ["*constant:*req.RequestType:*none"],
"Weight": 999
}]
})

See also:

Best Practices

1. Use Consistent Naming Conventions

# Good - clear relationship
ActionsId = "Action_premium-plan-100gb"
product_slug = "premium-plan-100gb"

# Bad - no clear relationship
ActionsId = "Action_Plan_A"
product_slug = "premium_100"

2. Define Actions Before Products

Always create CGRateS Actions before creating CRM products. The provisioning playbook will fail if it tries to execute a non-existent Action.

3. Include CDR Logging

Always add *cdrlog action to track balance additions:

{
"Identifier": "*cdrlog",
"BalanceType": "*generic",
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Product Name\"}",
"Weight": 80
}

4. Use Descriptive Balance IDs

# Good
"BalanceId": "Premium_Data_100GB"
"BalanceId": "AU_Voice_Domestic__" + str(units)

# Bad
"BalanceId": "data1"
"BalanceId": "balance"

5. Document Units Clearly

# Good - shows calculation
Units = 100 * 1024 * 1024 * 1024 # 100GB in bytes
Units = 3000 * 60 * 1000000000 # 3000 minutes in nanoseconds

# Bad - magic number
Units = 107374182400

6. Use Weight Strategically

Higher weight = higher priority for both execution and consumption:

# Execution order (higher weight = executes first)
{"Identifier": "*reset_account", "Weight": 700}
{"Identifier": "*topup_reset", "Weight": 90}
{"Identifier": "*cdrlog", "Weight": 80}

# Balance consumption (higher weight = consumed first)
"BalanceWeight": 1200 # Premium/domestic balances
"BalanceWeight": 1100 # Roaming balances
"BalanceWeight": 1000 # International balances

7. Test with Small Values First

When defining new products, test with small balances first:

# Testing
Units = 100 * 1024 * 1024 # 100MB for testing

# Production
Units = 100 * 1024 * 1024 * 1024 # 100GB

Troubleshooting

Error: "Action not found"

Symptom: Playbook fails with "Action not found" or "ActionsId does not exist"

Cause: Action not defined in CGRateS, or naming mismatch

Solution:

  1. Verify Action exists: Query CGRateS for the Action
  2. Check naming: Ensure ActionsId = "Action_" + product_slug
  3. Define the Action if missing

Error: "Destination not found"

Symptom: Action executes but balances not created

Cause: DestinationIDs references non-existent destination

Solution:

  1. Define the destination in CGRateS first
  2. Use *any for universal destinations
  3. Check spelling of destination IDs

Product Created But No Balances Added

Symptom: Product provisions successfully but customer has no balance

Cause: Action exists but has no balance-adding operations

Solution:

  1. Verify Action has *topup or *topup_reset operations
  2. Check Units value is correct (not 0)
  3. Verify ExpiryTime hasn't already passed

Balances Not Rolling Over

Symptom: Using rollover but unused balance disappears

Cause: Using *topup_reset instead of *topup

Solution:

  • Change Identifier from *topup_reset to *topup
  • Ensure BalanceId is consistent across topups

See also: CGRateS Actions and Topup Behaviors

Summary

This guide demonstrates one common approach to configuring products in OmniCRM with CGRateS. The patterns shown here work well for typical mobile virtual network operator (MVNO) use cases with prepaid/postpaid plans, data packages, and roaming.

Remember: CGRateS is capable of far more sophisticated scenarios than covered here. If you need advanced features like:

  • Differential MO/MT pricing for roaming voice and SMS
  • CAMEL-based charging for 2G/3G legacy devices
  • Time-of-day or seasonal rate variations
  • Customer tier-based pricing (bronze/silver/gold)
  • Network quality or QoS-based charging
  • Least-cost routing with multiple suppliers

...consult the CGRateS documentation directly and work with your rating plan configuration independently of the CRM product definitions.