Routing Plugin
Operational Mode: Plugin. Extend Plauti Assign with custom Apex logic for routing and SLA escalation
This article explains how to extend Plauti Assign by implementing a custom Apex class that follows global interface srrPluginInterface. Plugins allow you to customize matching, assignee filtering, assignment logic, and react to SLA escalation events.
Overview
A plugin lets you override or extend standard Plauti Assign behavior. The plugin framework supports two categories of events:
Routing Events (MatchGroup Plugin Mode)
When a MatchGroup is set to Operational Mode: Plugin, Plauti Assign emits routing events that your class may handle:
| Event | Purpose |
|---|---|
| MATCHGROUP_MATCH | Decide if the incoming record matches the MatchGroup, or defer to normal rules. |
| MATCHGROUP_ASSIGNEE_FILTER | Recalculate or filter the available assignees for the matched record; return the list that Plauti Assign should use going forward. |
| MATCHGROUP_ASSIGN | Decide how a matched record is assigned (specific user, queue, round-robin, load-balance). |
SLA Events (Automatic)
SLA events fire automatically when certain conditions are met, regardless of MatchGroup operational mode:
| Event | Purpose |
|---|---|
| ASSIGNMENT_SLA_MAX_REASSIGNMENT | React when a record reaches its SLA reassignment limit (fire-and-forget, no return value). |
Event TypesRouting events affect the assignment outcomeโyour plugin returns a result that Plauti Assign uses to determine what happens next.
SLA events are fire-and-forget notificationsโthe assignment has already occurred, and your plugin performs side effects like escalation workflows, notifications, or field updates.
isAvailable(eventType) is invoked first; return true for the events your plugin supports.
Routing Events
MATCHGROUP_ASSIGNEE_FILTER
The plugin is used to recalculate the available assignees of a match group based on the customer's business rules. The plugin receives the record that is currently being assigned, the match group that has been matched to the record, and the list of available assignees, according to the business rules configured in Plauti Assign. The plugin returns the list of assignees that Plauti Assign should use to run the assignment logic specified via the match group's operational mode.
Routing Implementation
Core interface & example
The sample plugin checks the record's LastName: it flags "Carpenter" as a direct match, "Meadow" as no-match, and "Gilmore" as "run rules," otherwise it does nothing. If the record is a match, it:
- Filters the assignee list so "Carpenter" records only consider the user with alias jos, blocks "Meadow" by returning an empty list, and leaves "Gilmore" unchanged. Other surnames exclude the record's current owner.
- Assigns "Carpenter" records to the user with alias jos, throws an exception for "Meadow," routes "Gilmore" to the MatchGroup's queue user, and load-balances any other surname.
global class MySrrPlugin implements srrPluginInterface {
// Define which events this plugin supports
private static final Set<String> SUPPORTED = new Set<String>{
'MATCHGROUP_MATCH', 'MATCHGROUP_ASSIGNEE_FILTER', 'MATCHGROUP_ASSIGN'
};
// isAvailable is called by the framework to check if we handle a given event
public Boolean isAvailable(srrPlugin.PluginEventType evt) {
return SUPPORTED.contains(evt.name());
}
// execute dispatches incoming events to the appropriate handler
public Object execute(srrPlugin.PluginEventType evt, Object data) {
switch on evt {
when MATCHGROUP_MATCH {
return match((srrPluginModel.MatchGroupMatchInput) data);
}
when MATCHGROUP_ASSIGNEE_FILTER {
return assigneeFilter((srrPluginModel.AssigneeFilterInput) data);
}
when MATCHGROUP_ASSIGN {
return assign((srrPluginModel.MatchGroupAssignInput) data);
}
when else {
return null;
}
}
}
/* ---------- Matching logic ---------- */
private srrPluginModel.MatchGroupMatchOutput match(
srrPluginModel.MatchGroupMatchInput in) {
// Prepare output container
srrPluginModel.MatchGroupMatchOutput out =
new srrPluginModel.MatchGroupMatchOutput();
// Null-safe fetch of LastName using SObject.isSet
String lastName;
if (in != null
&& in.objectToMatch != null
&& in.objectToMatch.isSet('LastName')
&& in.objectToMatch.get('LastName') != null) {
lastName = String.valueOf(in.objectToMatch.get('LastName'));
} else {
lastName = null;
}
// Custom matching rules based on LastName value
if (lastName == 'Carpenter') {
// Always treat 'Carpenter' as a match
out.matchResult = srrPluginModel.MatchResult.MATCH;
} else if (lastName == 'Meadow') {
// Always skip 'Meadow' (no match), continue to next MatchGroup
out.matchResult = srrPluginModel.MatchResult.NO_MATCH;
} else if (lastName == 'Gilmore') {
// Defer to the MatchGroup's own rules for 'Gilmore'
out.matchResult = srrPluginModel.MatchResult.RUN_RULES;
}
// Return the chosen MatchResult
return out;
}
/* ---------- Assignee filtering logic ---------- */
// Return the list of assignees Plauti Assign should use in subsequent assignment logic.
private srrPluginModel.AssigneeFilterOutput assigneeFilter(
srrPluginModel.AssigneeFilterInput in) {
srrPluginModel.AssigneeFilterOutput out =
new srrPluginModel.AssigneeFilterOutput();
out.assigneeList = new List<Assignee__c>();
String lastName;
if (in != null
&& in.objectToAssign != null
&& in.objectToAssign.isSet('LastName')
&& in.objectToAssign.get('LastName') != null) {
lastName = String.valueOf(in.objectToAssign.get('LastName'));
} else {
lastName = null;
}
if (lastName == 'Carpenter') {
// Restrict to just the user with alias 'jos'
User u = [SELECT Id FROM User WHERE Alias = 'jos' LIMIT 1];
if (in != null && in.assigneeList != null) {
for (Assignee__c a : in.assigneeList) {
// Guard dynamic get with isSet
if (a != null && a.isSet('User__c') && (Id)a.get('User__c') == u.Id) {
out.assigneeList.add(a);
break; // keep only the 'jos' assignee
}
}
}
} else if (lastName == 'Meadow') {
// Return an empty list to prevent assignment with the current MatchGroup
return out;
} else if (lastName == 'Gilmore') {
// Do not change the list; allow normal group logic to proceed
out.assigneeList = in.assigneeList;
return out;
} else {
// Exclude the record's current owner from consideration (null-safe with isSet)
Id ownerId = null;
if (in != null
&& in.objectToAssign != null
&& in.objectToAssign.isSet('OwnerId')
&& in.objectToAssign.get('OwnerId') != null) {
ownerId = (Id) in.objectToAssign.get('OwnerId');
}
if (in != null && in.assigneeList != null) {
for (Assignee__c a : in.assigneeList) {
if (a == null) continue;
Id assigneeUserId = null;
if (a.isSet('User__c') && a.get('User__c') != null) {
assigneeUserId = (Id) a.get('User__c');
}
if (ownerId == null || assigneeUserId != ownerId) {
out.assigneeList.add(a);
}
}
}
}
return out;
}
/* ---------- Assignment logic ---------- */
private srrPluginModel.MatchGroupAssignOutput assign(
srrPluginModel.MatchGroupAssignInput in) {
srrPluginModel.MatchGroupAssignOutput out =
new srrPluginModel.MatchGroupAssignOutput();
String lastName;
if (in != null
&& in.objectToAssign != null
&& in.objectToAssign.isSet('LastName')
&& in.objectToAssign.get('LastName') != null) {
lastName = String.valueOf(in.objectToAssign.get('LastName'));
} else {
lastName = null;
}
if (lastName == 'Carpenter') {
// Query the User with alias 'jos'
User u = [SELECT Id FROM User WHERE Alias='jos' LIMIT 1];
// Find the corresponding Assignee__c in the provided list
if (in != null && in.assigneeList != null) {
for (Assignee__c a : in.assigneeList) {
if (a != null && a.isSet('User__c') && a.get('User__c') != null
&& (Id)a.get('User__c') == u.Id) {
out.assignee = a;
break;
}
}
}
if (out.assignee == null) {
// Either add an Assignee__c to the list or throw, based on your policy
throw new srrPlugin.PluginException(
'Required Assignee__c for user alias "jos" was not found in assigneeList.');
}
// Instruct SRR to assign to that specific user
out.assignResult = srrPluginModel.AssignResult.ASSIGNED;
} else if (lastName == 'Meadow') {
// Throw an exception if trying to assign a record we declared NO_MATCH
throw new srrPlugin.PluginException(
'Plugin declared NO_MATCH or returned no assignees โ assignment prohibited.');
} else if (lastName == 'Gilmore') {
// Send 'Gilmore' records to the MatchGroup's Queue User
out.assignResult = srrPluginModel.AssignResult.QUEUE;
} else {
// All other matched records are load-balanced across assignees
out.assignResult = srrPluginModel.AssignResult.RUN_LOAD_BALANCED;
}
// Return the chosen AssignResult (and assignee if applicable)
return out;
}
}Step 1 โ Create the Apex Class
Create a global class (visibility is required so Type.forName can instantiate it) that implements srrPluginInterface.
Step 2 โ Handle MATCHGROUP_MATCH
- Input DTO:
srrPluginModel.MatchGroupMatchInputwith matchGroup and objectToMatch. - Return DTO:
srrPluginModel.MatchGroupMatchOutputwith one ofMATCH,NO_MATCH,RUN_RULESinmatchResult. - Null-safety: guard with
SObject.isSet('LastName')before calling.get; verify non-null beforeString.valueOf.
Step 3 โ Handle MATCHGROUP_ASSIGNEE_FILTER
- Input DTO:
srrPluginModel.AssigneeFilterInputwith matchGroup, assigneeList, objectToAssign. - Return DTO:
srrPluginModel.AssigneeFilterOutputwith a filteredassigneeListthat Plauti Assign will use for subsequent assignment logic. - Use this to apply custom business rules that narrow or reorder the available assignees for the matched record.
- If you return an empty list, downstream behavior depends on the MatchGroup's operational mode and configuration.
- Null-safety: use
SObject.isSet('LastName')andSObject.isSet('OwnerId')before.get; check for nulls beforeString.valueOfor casts.
Step 4 โ Handle MATCHGROUP_ASSIGN
- Input DTO:
srrPluginModel.MatchGroupAssignInputwith matchGroup, assigneeList (possibly filtered by your plugin), objectToAssign. - Return DTO:
srrPluginModel.MatchGroupAssignOutputwith one ofASSIGNED,QUEUE,RUN_ROUNDROBIN,RUN_LOAD_BALANCED. - If you return
ASSIGNED, the chosenAssignee__cmust exist in or be added to the list. - Null-safety: guard with
SObject.isSet('LastName')before.get; verify non-null beforeString.valueOf.
Step 5 โ Register the Plugin
In Setup โบ Custom Metadata Types โบ SRR Options (leadassist__SRR_Options__mdt) edit the record with Developer Name = Plugin_Class_Name and set Value to the fully-qualified class name (e.g. MySrrPlugin).
Step 6 โ Enable Plugin Mode on the MatchGroup
Open the MatchGroup, edit Operational Mode, choose Plugin, and save.
Routing Results
| Enum | Meaning |
|---|---|
MatchResult: MATCH | Record instantly matches this MatchGroup. |
MatchResult: NO_MATCH | Record bypasses this MatchGroup. |
MatchResult: RUN_RULES | Plauti Assign evaluates the group's MatchRules to decide. |
AssignResult: ASSIGNED | Assign to the specific Assignee__c supplied by the plugin. |
AssignResult: QUEUE | Assign to the MatchGroup's Queue User. |
AssignResult: RUN_ROUNDROBIN | Assign to the next assignee in round-robin order. |
AssignResult: RUN_LOAD_BALANCED | Assign to the least-loaded assignee in the group. |
For MATCHGROUP_ASSIGNEE_FILTER, the plugin returns srrPluginModel.AssigneeFilterOutput containing a List of type: Assignee__c that Plauti Assign uses as the candidate set for subsequent assignment logic.
Routing Flow
flowchart TD
A["Record Received"] --> B{"MatchGroup in Plugin Mode?"}
B -- "No" --> C["Standard Plauti Assign Process"] --> Z["End"]
B -- "Yes" --> D["MATCHGROUP_MATCH (plugin)"]
D --> E{"MatchResult"}
E -- "MATCH" --> MAF["MATCHGROUP_ASSIGNEE_FILTER (plugin)"]
E -- "NO_MATCH" --> I["End (No Match)"]
E -- "RUN_RULES" --> F["Evaluate MatchRules"]
F --> G{"Matched after rules?"}
G -- "Yes" --> MAF
G -- "No" --> I
MAF --> H["MATCHGROUP_ASSIGN (plugin)"]
H --> J{"AssignResult"}
J -- "ASSIGNED" --> P1["Assign to specific assignee (plugin)"]
J -- "QUEUE" --> P2["Assign to MatchGroup queue user"]
J -- "RUN_ROUNDROBIN" --> P3["Assign next assignee (round-robin)"]
J -- "RUN_LOAD_BALANCED" --> P4["Assign least-loaded assignee"]
P1 --> P["Record Assigned"]
P2 --> P
P3 --> P
P4 --> P
The plugin receives full context DTOs so you can query additional data, log diagnostics, or dynamically build Assignee__c records as needed. Use MATCHGROUP_ASSIGNEE_FILTER to enforce business-specific eligibility and prioritization before the assignment algorithm runs. Ensure .get calls are guarded with SObject.isSet and null checks before String.valueOf.
SLA Max Reassignment Event
Overview
Plauti Assign's SLA feature automatically reassigns records when response deadlines are missed. To prevent endless "ping-pong" between assignees, you can configure a Max Reassignments limit on the SLA. When this limit is reached:
- The record is assigned to a fallback user (the SLA User if configured, otherwise the MatchGroup's Queue User)
- The record's
Use_Round_Robin__cfield is set toASSIGNED - A MatchLog is created with the note "SLA reassignment limit reached. Assigned to fallback user."
- The
ASSIGNMENT_SLA_MAX_REASSIGNMENTplugin event fires
This plugin event allows you to execute custom escalation logicโfor example:
- Update escalation-related fields (priority, status, escalation level)
- Set Use Plauti Assign = TRUE to re-evaluate the record across other MatchGroups (e.g., escalation or backup teams)
- Create escalation cases or send notifications
- Log to external systems
When is this event fired?
The ASSIGNMENT_SLA_MAX_REASSIGNMENT event fires when all of the following conditions are met:
- An SLA has Reassign If SLA Missed enabled
- The SLA has a Max Reassignments value configured
- A record's SLA expires and the current reassignment count is greater than or equal to the Max Reassignments limit
- A fallback user is available (either SLA User on the SLA, or Queue User on the MatchGroup)
Fire-and-forget eventUnlike the routing plugin events, this event does not affect the assignment outcome. The record has already been assigned to the fallback user before the plugin executes. Use this event for side effects like escalation workflows, notifications, or triggering re-evaluation by other MatchGroups.
Related SLA Fields
The following fields are used by the Max Reassignments feature:
| Object | Field | Description |
|---|---|---|
| SLA__c | Max_Reassignments__c | Maximum number of times a record can be automatically reassigned when this SLA is missed. Leave blank for unlimited. |
| SLA__c | SLA_User__c | Fallback owner when the reassignment limit is reached. |
| SLA__c | Skip_Previously_Assigned__c | Controls which previously assigned users are excluded from reassignment: DO_NOT_SKIP, SKIP_LAST, or SKIP_ALL. |
| MatchLogSLA__c | Limit_Reached__c | Checkbox indicating this SLA reached its maximum reassignment limit. |
| MatchLogSLA__c | Reassignment_Count__c | The number of times this record had been reassigned at the time this SLA was created. |
SLA Implementation
Example plugin
The sample plugin updates the Lead's Description field with escalation information when the SLA reassignment limit is reached.
public with sharing class SLAMaxReassignmentPlugin implements srrPluginInterface {
// Define which events this plugin supports
public Boolean isAvailable(srrPlugin.PluginEventType evt) {
return evt == srrPlugin.PluginEventType.ASSIGNMENT_SLA_MAX_REASSIGNMENT;
}
// execute dispatches incoming events to the appropriate handler
public Object execute(srrPlugin.PluginEventType evt, Object data) {
if (evt == srrPlugin.PluginEventType.ASSIGNMENT_SLA_MAX_REASSIGNMENT) {
handleSLAMaxReassignment((srrPluginModel.SLAMaxReassignmentInput) data);
}
return null; // Fire-and-forget event, return value is ignored
}
/* ---------- SLA Max Reassignment handler ---------- */
private void handleSLAMaxReassignment(srrPluginModel.SLAMaxReassignmentInput input) {
// Only process Leads in this example
if (input.recordId == null ||
input.recordId.getSObjectType() != Lead.SObjectType) {
return;
}
// Get MatchGroup name for context
String matchGroupName = '';
if (input.matchGroupId != null) {
List<MatchGroup__c> mgs = [
SELECT Name
FROM MatchGroup__c
WHERE Id = :input.matchGroupId
LIMIT 1
];
if (!mgs.isEmpty()) {
matchGroupName = mgs[0].Name;
}
}
// Update Lead Description with escalation info
Lead l = new Lead(
Id = input.recordId,
Description = 'SLA Max Reassignment reached. ' +
'MatchGroup: ' + matchGroupName + ', ' +
'Reassignment Count: ' + input.reassignmentCount
);
update l;
}
}Step 1 โ Create the Apex Class
Create a class that implements srrPluginInterface. Unlike routing plugins, this class does not need to be global unless you need external access.
Step 2 โ Handle ASSIGNMENT_SLA_MAX_REASSIGNMENT
- Input DTO:
srrPluginModel.SLAMaxReassignmentInputwith matchGroupId, recordId, slaId, and reassignmentCount. - Return:
null(return value is ignoredโthis is a fire-and-forget event). - Use this to trigger escalation workflows, update fields, send notifications, or re-trigger assignment.
- The record has already been assigned to the fallback user before this event fires.
- Exceptions in the plugin are caught and logged but do not prevent the fallback assignment from completing.
Step 3 โ Register the Plugin
In Setup โบ Custom Metadata Types โบ SRR Options (leadassist__SRR_Options__mdt) edit the record with Developer Name = Plugin_Class_Name and set Value to the fully-qualified class name (e.g. SLAMaxReassignmentPlugin).
Step 4 โ Configure SLA Max Reassignments
- Open the SLA record you want to limit.
- Set Max Reassignments to the maximum number of times a record should be reassigned.
- Optionally set SLA User as the fallback owner when the limit is reached. If not set, the MatchGroup's Queue User is used.
- Optionally configure Skip Previously Assigned to prevent records from bouncing back to assignees who missed the SLA.
- Save the SLA.
SLA Input Model
The SLAMaxReassignmentInput class provides the following properties:
| Property | Type | Description |
|---|---|---|
| matchGroupId | Id | The MatchGroup Id where the SLA limit was reached. |
| recordId | Id | The Record Id that hit the reassignment limit. |
| slaId | Id | The SLA Id that was missed when the limit was reached. |
| reassignmentCount | Integer | The number of times this record has been reassigned via SLA. |
SLA Use Cases
Escalate to a backup team
The most powerful use of this plugin is to re-trigger Plauti Assign so the record is evaluated by other MatchGroupsโsuch as escalation teams, backup teams, or higher-tier support groups.
private void handleSLAMaxReassignment(srrPluginModel.SLAMaxReassignmentInput input) {
if (input.recordId == null) return;
// Only handle Leads
if (input.recordId.getSObjectType() != Lead.SObjectType) return;
// Update escalation fields and re-trigger Plauti Assign
// This allows the record to match against other MatchGroups
// (e.g., an "Escalation Team" MatchGroup with different rules)
Lead l = new Lead(
Id = input.recordId,
Use_Round_Robin__c = 'TRUE', // Re-trigger Plauti Assign
Escalation_Level__c = 'Tier 2', // Custom field for escalation tracking
Priority__c = 'High' // Increase priority
);
update l;
}
Tip: Create a separate MatchGroup for your escalation team with rules that match escalated records (e.g.,Escalation_Level__c = 'Tier 2'). When the plugin setsUse_Round_Robin__c = 'TRUE', the record will be re-evaluated and can match the escalation MatchGroup, starting a new SLA cycle with the backup team.
Update escalation-related fields
private void handleSLAMaxReassignment(srrPluginModel.SLAMaxReassignmentInput input) {
if (input.recordId == null) return;
// Build dynamic update for escalation fields
SObject record = input.recordId.getSObjectType().newSObject(input.recordId);
// Set common escalation fields (adjust field names to your org)
record.put('Status', 'Escalated');
record.put('Priority', 'High');
record.put('Escalation_Reason__c',
'SLA missed ' + input.reassignmentCount + ' times');
record.put('Escalated_Date__c', System.now());
update record;
}Create an escalation Case
private void handleSLAMaxReassignment(srrPluginModel.SLAMaxReassignmentInput input) {
if (input.recordId == null) return;
// Query the record for context
String sObjectType = String.valueOf(input.recordId.getSObjectType());
String recordName = '';
try {
Id recordId = input.recordId;
SObject record = Database.query(
'SELECT Id, Name FROM ' + String.escapeSingleQuotes(sObjectType) +
' WHERE Id = :recordId LIMIT 1'
);
recordName = (String) record.get('Name');
} catch (Exception e) {
recordName = String.valueOf(input.recordId);
}
// Create escalation Case
Case escalation = new Case(
Subject = 'SLA Escalation: ' + recordName,
Description = 'Record has exceeded maximum SLA reassignments (' +
input.reassignmentCount + '). Requires manual review.',
Priority = 'High',
Origin = 'SLA Escalation'
);
insert escalation;
}Send a Platform Event notification
private void handleSLAMaxReassignment(srrPluginModel.SLAMaxReassignmentInput input) {
// Publish a platform event for downstream processing
SLA_Escalation__e evt = new SLA_Escalation__e(
Record_Id__c = input.recordId,
MatchGroup_Id__c = input.matchGroupId,
SLA_Id__c = input.slaId,
Reassignment_Count__c = input.reassignmentCount
);
EventBus.publish(evt);
}SLA Event Flow
flowchart TD
A["SLA Expires"] --> B{"Reassign If SLA Missed?"}
B -- "No" --> Z1["Mark SLA as Missed"] --> Z["End"]
B -- "Yes" --> C{"Max Reassignments configured?"}
C -- "No" --> D["Normal Reassignment (set URR=QUEUED)"] --> Z
C -- "Yes" --> E{"Current count >= Max?"}
E -- "No" --> D
E -- "Yes" --> F["Assign to SLA User or Queue User"]
F --> G["Set URR=ASSIGNED"]
G --> H["Create MatchLog with limit note"]
H --> I["Set Limit_Reached__c = true"]
I --> J{"Plugin registered?"}
J -- "No" --> Z
J -- "Yes" --> K["Fire ASSIGNMENT_SLA_MAX_REASSIGNMENT"]
K --> L["Plugin executes (exceptions caught)"]
L --> Z
Combining Events
You can implement multiple plugin events in the same class. Use isAvailable() to declare which events your plugin handles:
global class CombinedPlugin implements srrPluginInterface {
public Boolean isAvailable(srrPlugin.PluginEventType evt) {
return evt == srrPlugin.PluginEventType.MATCHGROUP_ASSIGN
|| evt == srrPlugin.PluginEventType.ASSIGNMENT_SLA_MAX_REASSIGNMENT;
}
public Object execute(srrPlugin.PluginEventType evt, Object data) {
switch on evt {
when MATCHGROUP_ASSIGN {
return handleAssign((srrPluginModel.MatchGroupAssignInput) data);
}
when ASSIGNMENT_SLA_MAX_REASSIGNMENT {
handleSLAMaxReassignment((srrPluginModel.SLAMaxReassignmentInput) data);
return null;
}
when else {
return null;
}
}
}
private srrPluginModel.MatchGroupAssignOutput handleAssign(
srrPluginModel.MatchGroupAssignInput input) {
// Custom assignment logic
srrPluginModel.MatchGroupAssignOutput out =
new srrPluginModel.MatchGroupAssignOutput();
out.assignResult = srrPluginModel.AssignResult.RUN_LOAD_BALANCED;
return out;
}
private void handleSLAMaxReassignment(
srrPluginModel.SLAMaxReassignmentInput input) {
// Custom escalation logic
if (input.recordId != null) {
// Update record, create case, send notification, etc.
}
}
}Best Practices
-
Keep plugins lightweight: Plugins execute synchronously. Avoid heavy processing that could cause governor limit issues, especially for SLA events which run in a queueable context.
-
Handle exceptions gracefully: Wrap your logic in try-catch blocks. For SLA events, exceptions are caught and logged but do not prevent the fallback assignment from completing.
-
Use async processing for heavy operations: If you need to perform complex operations, consider publishing a Platform Event or enqueueing a separate Queueable job.
-
Filter by object type for SLA events: The
ASSIGNMENT_SLA_MAX_REASSIGNMENTevent fires for all object types. Useinput.recordId.getSObjectType()to filter for specific objects. -
Design escalation MatchGroups: Create separate MatchGroups for escalation or backup teams. Use matching rules based on escalation fields so records route correctly when re-triggered via the plugin.
-
Combine with Skip Previously Assigned: Enable Skip Previously Assigned on your SLA to prevent records from bouncing back to assignees who already missed the SLA.
-
Guard against null values: Always check for null values before accessing properties, especially when using
SObject.get()with dynamic field names.
Business Value
- Enforces predictable response times without endless internal "ping-pong" between assignees.
- Increases accountability by tracking reassignment counts and avoiding repeat assignment to non-responsive users.
- Supports structured escalation paths from primary teams to backup or higher-tier teams via plugin-triggered re-evaluation.
- Provides flexibility to implement org-specific routing logic and escalation workflows through custom Apex.
The plugin interface provides full context DTOs so you can query additional data, log diagnostics, create related records, or integrate with external systems. Routing events affect the assignment outcome, while SLA events enable custom escalation workflows after the assignment has occurred.
Updated 22 days ago