In our last post we added a series of different balances to an account, these were actions we took via the API specifically to add a balance.
But there’s a lot more actions we may want to do beyond just adding balance.
CGrateS has the concept of “Actions” which are, as the name suggests, things we want to do to the system.
Some example Actions would be:
- Adding / Deducting / Resetting a balance
- Adding a CDR log
- Enable/Disable an account
- Sending HTTP POST request or email notification
- Deleting / suspending account
- Transferring balances
We can run these actions on a timed basis, or when an event is triggered, and group Actions together to run multiple actions via an ActionTrigger, this means we can trigger these Actions, not just by sending an API request, but based on the state of the subscriber / account.
Let’s look at some examples,
We can define an Action named “Action_Monthly_Fee” to debit $12 from the monetary balance of an account, and add a CDR with the name “Monthly Account Fee” when it does so.
We can use ActionTriggers to run this every month on the account automatically.
We can define an Action named “Usage_Warning_10GB” to send an email to the Account owner to inform them they’ve used 10GB of usage, and use ActionTriggers to send this when the customer has used 10GB of their *data balance.
Using Actions
Note: The Python script I’ve used with all the examples in this post is available on GitHub here.
Let’s start by defining an Account, just as we have before:
# Create the Account object inside CGrateS
Account = "Nick_Test_123"
Create_Account_JSON = {
"method": "ApierV2.SetAccount",
"params": [
{
"Tenant": "cgrates.org",
"Account": str(Account)
}
]
}
print(CGRateS_Obj.SendData(Create_Account_JSON))
Let’s start basic; to sweeten the deal for new Accounts, we’ll give them $99 of balance to use in the first month they have the service. Rather than hitting the AddBalance API, we’ll define an Action named “Action_Add_Signup_Bonus” to credit $99 of monetary balance to an account.
If you go back to our last post, you should know what we’d need to do to add this balance manually with the AddBalance API, but let’s look at how we can create the same balance add functionality using Actions:
#Add a Signup Bonus of $99 to the account with type *monetary expiring a month after it's added
Action_Signup_Bonus = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [
{
"ActionsId": "Action_Add_Signup_Bonus",
"Actions": [
{
"Identifier": "*topup",
"BalanceId": "Balance_Signup_Bonus",
"BalanceUuid": "",
"BalanceType": "*monetary",
"Directions": "*out",
"Units": 99,
"ExpiryTime": "*month",
"Filter": "",
"TimingTags": "",
"DestinationIds": "",
"RatingSubject": "",
"Categories": "",
"SharedGroups": "",
"BalanceWeight": 1200,
"ExtraParameters": "",
"BalanceBlocker": "false",
"BalanceDisabled": "false",
"Weight": 10
}
]}]}
pprint.pprint(CGRateS_Obj.SendData(Action_Signup_Bonus))
Alright, this should look pretty familiar if you’ve just come from Account Balances.
You’ll notice we’re no longer calling, SetBalance, we’re now calling SetActions, to create the ActionsId with the name “Action_Add_Signup_Bonus“.
In “Action_Add_Signup_Bonus” we’ve got an actions we’ll do when “Action_Add_Signup_Bonus” is called.
We can define multiple actions, but for now we’ve only got one action defined, which has the Identifier (which defines what the action does) set to *topup to add balance.
As you probably guessed, we’re triggering a top up, and setting the BalanceId, BalanceType, Units, ExpiryTime and BalanceWeight just as we would using SetBalance to add a balance.
So how do we use the Action we just created? Well, there’s a lot of options, but let’s start with the most basic – Via the API:
# Trigger ExecuteAction
Account_Action_trigger_JSON = {"method": "APIerSv1.ExecuteAction", "params": [
{"Tenant": "cgrates.org", "Account": str(Account), "ActionsId": "Action_Add_Signup_Bonus"}]}
pprint.pprint(CGRateS_Obj.SendData(Account_Action_trigger_JSON))
Boom, we’ve called the ExecuteAction API call, to execute the Action named “Action_Add_Signup_Bonus“.
We can check on this with GetAccount again and check the results:
# Get Account Info
pprint.pprint(CGRateS_Obj.SendData({'method': 'ApierV2.GetAccount', 'params': [
{"Tenant": "cgrates.org", "Account": str(Account)}]}))
{'method': 'ApierV2.GetAccount', 'params': [{'Tenant': 'cgrates.org', 'Account': 'Nick_Test_123'}]} {'error': None, 'id': None, 'result': {'ActionTriggers': None, 'AllowNegative': False, 'BalanceMap': {'*monetary': [{'Blocker': False, 'Categories': {}, 'DestinationIDs': {}, 'Disabled': False, 'ExpirationDate': '2023-11-15T10:27:52.865119544+11:00', 'Factor': None, 'ID': 'Balance_Signup_Bonus', 'RatingSubject': '', 'SharedGroups': {}, 'TimingIDs': {}, 'Timings': None, 'Uuid': '01cfb471-ba38-453a-b0e2-8ddb397dfe9c', 'Value': 99, 'Weight': 1200}]}, 'Disabled': False, 'ID': 'cgrates.org:Nick_Test_123', 'UnitCounters': None, 'UpdateTime': '2023-10-15T10:27:52.865144268+11:00'}}
Great start!
Making Actions Useful
Well congratulations, we took something we previously did with one API call (SetBalance), and we did it with two (SetAction and ExcecuteAction)!
But let’s start paying efficiency dividends,
When we add a balance, let’s also add a CDR log event so we’ll know the account was credited with the balance when we call the GetCDRs API call.
We’d just modify our SetActions to include an extra step:
Action_Signup_Bonus = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [
{
"ActionsId": "Action_Add_Signup_Bonus",
"Actions": [
{
"Identifier": "*topup",
"BalanceId": "Balance_Signup_Bonus",
...
},
{
"Identifier": "*cdrlog",
"BalanceId": "",
"BalanceUuid": "",
"BalanceType": "*monetary",
"Directions": "*out",
"Units": 0,
"ExpiryTime": "",
"Filter": "",
"TimingTags": "",
"DestinationIds": "",
"RatingSubject": "",
"Categories": "",
"SharedGroups": "",
"BalanceWeight": 0,
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Your sign up Bonus\"}",
"BalanceBlocker": "false",
"BalanceDisabled": "false",
"Weight": 10
}
]}]}
pprint.pprint(CGRateS_Obj.SendData(Action_Signup_Bonus))
Boom, now we’ll get a CDR created when the Action is triggered.
But let’s push this a bit more and add some more steps in the Action:
As well as adding balance and putting in a CDR to record what we did, let’s also send a notification to our customer via an HTTP API (BYO customer push notification system) and log to Syslog what’s going on.
# Add a Signup Bonus of $99 to the account with type *monetary expiring a month after it's added
Action_Signup_Bonus = {
"id": "0",
"method": "ApierV1.SetActions",
"params": [
{
"ActionsId": "Action_Add_Signup_Bonus",
"Actions": [
{
"Identifier": "*topup",
"BalanceId": "Balance_Signup_Bonus",
"BalanceUuid": "",
"BalanceType": "*monetary",
"Directions": "*out",
"Units": 99,
"ExpiryTime": "*month",
"Filter": "",
"TimingTags": "",
"DestinationIds": "",
"RatingSubject": "",
"Categories": "",
"SharedGroups": "",
"BalanceWeight": 1200,
"ExtraParameters": "",
"BalanceBlocker": "false",
"BalanceDisabled": "false",
"Weight": 90
},
{
"Identifier": "*cdrlog",
"BalanceId": "",
"BalanceUuid": "",
"BalanceType": "*monetary",
"Directions": "*out",
"Units": 0,
"ExpiryTime": "",
"Filter": "",
"TimingTags": "",
"DestinationIds": "",
"RatingSubject": "",
"Categories": "",
"SharedGroups": "",
"BalanceWeight": 0,
"ExtraParameters": "{\"Category\":\"^activation\",\"Destination\":\"Your sign up Bonus\"}",
"BalanceBlocker": "false",
"BalanceDisabled": "false",
"Weight": 80
},
{
"Identifier": "*http_post_async",
"ExtraParameters": "http://10.177.2.135/example_endpoint",
"ExpiryTime": "*unlimited",
"Weight": 70
},
{
"Identifier": "*log",
"Weight": 60
}
]}]}
pprint.pprint(CGRateS_Obj.SendData(Action_Signup_Bonus))
Phew! That’s a big action, but if we execute the action again using ExecuteAction, we’ll get all these things happening at once:



Okay, now we’re getting somewhere!
ActionPlans
Having an Action we can trigger manually via the API is one thing, but being able to trigger it automatically is where it really comes into its own.
Let’s define an ActionPlan, that is going to call our Action named “Action_Add_Signup_Bonus” as soon as the ActionPlan is assigned to an Account.
# Create ActionPlan using SetActionPlan to trigger the Action_Signup_Bonus ASAP
SetActionPlan_Signup_Bonus_JSON = {
"method": "ApierV1.SetActionPlan",
"params": [{
"Id": "ActionPlan_Signup_Bonus",
"ActionPlan": [{
"ActionsId": "Action_Add_Signup_Bonus",
"Years": "*any",
"Months": "*any",
"MonthDays": "*any",
"WeekDays": "*any",
"Time": "*asap",
"Weight": 10
}],
"Overwrite": True,
"ReloadScheduler": True
}]
}
pprint.pprint(CGRateS_Obj.SendData(SetActionPlan_Signup_Bonus_JSON))
So what have we done here? We’ve made an ActionPlan named “Action_Add_Signup_Bonus”, which, when associated with an account, will run the Action “Action_Add_Signup_Bonus” as soon as it’s tied to the account, thanks to the Time “*asap“.
Now if we create or update an Account using the SetAccount method, we can set the ActionPlanIds to reference our “ActionPlan_Signup_Bonus” and it’ll be triggered straight away.
# Create the Account object inside CGrateS
Create_Account_JSON = {
"method": "ApierV2.SetAccount",
"params": [
{
"Tenant": "cgrates.org",
"Account": str(Account),
"ActionPlanIds": ["ActionPlan_Signup_Bonus"],
"ActionPlansOverwrite": True,
"ReloadScheduler":True
}
]
}
print(CGRateS_Obj.SendData(Create_Account_JSON))
Now if we were to run a GetAccount API call, we’ll see the Account balance assigned that was created by the action Action_Add_Signup_Bonus which was triggered by ActionPlan assigned to the account:
{'method': 'ApierV2.GetAccount', 'params': [{'Tenant': 'cgrates.org', 'Account': 'Nick_Test_123'}]} {'error': None, 'id': None, 'result': {'ActionTriggers': None, 'AllowNegative': False, 'BalanceMap': {'*monetary': [{'Blocker': False, 'Categories': {}, 'DestinationIDs': {}, 'Disabled': False, 'ExpirationDate': '2023-11-16T12:41:02.530985381+11:00', 'Factor': None, 'ID': 'Balance_Signup_Bonus', 'RatingSubject': '', 'SharedGroups': {}, 'TimingIDs': {}, 'Timings': None, 'Uuid': '7bdbee5c-0888-4da2-b42f-5d6b8966ee2d', 'Value': 99, 'Weight': 1200}]}, 'Disabled': False, 'ID': 'cgrates.org:Nick_Test_123', 'UnitCounters': None, 'UpdateTime': '2023-10-16T12:41:12.7236096+11:00'}}
But here’s where it gets interesting, in the ActionPlan we just defined the Time was set to “*asap“, which means the Action is triggered as soon as it was assigned to the account, but if we set the Time value to “*monthly“, the Action would get triggered every month, or *every_minute to trigger every minute, or *month_end to trigger at the end of every month.
Code for these examples is available here.
I’m trying to keep these posts shorter as there’s a lot to cover. Stick around for our next post, we’ll look at some more ActionTriggers to keep decreasing the balance of the account, and setting up ActionTriggers to send a notification to the customer to tell them when their balance is getting low, or any other event based Action you can think of!