NotificationActionHandler Interface

Implement this interface to execute an action on a custom notification.

Namespace

Messaging

NotificationActionHandler Methods

The following are methods for NotificationActionHandler.

executeAction(actionableNotification)

Executes the actionable notification.

Signature

public Messaging.ActionResult executeAction(Messaging.ActionableNotification actionableNotification)

Parameters

Return Value

Type: Messaging.ActionResult

NotificationActionHandler Example Implementation

This is an example implementation of the Messaging.NotificationActionHandler interface.
global class CaseNotificationActionHandler implements Messaging.NotificationActionHandler {
    
    private static final String ACTION_REASSIGN_TO_QUEUE = 'reassignToQueue';
   private static final String DEFAULT_QUEUE_NAME = 'Queue_Exec'; // Default queue name, can be customized
    
    global Messaging.ActionResult executeAction(Messaging.ActionableNotification actionableNotification) {
        try {
            String actionIdentifier = actionableNotification.getActionIdentifier();
            String targetId = actionableNotification.getTargetId();
            
            if (String.isBlank(actionIdentifier) || String.isBlank(targetId)) {
                return new Messaging.ActionResult.Builder()
                    .withSuccess(false)
                    .withMessage('Action identifier and target ID are required')
                    .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
                    .build();
            }
            
            // Validate that targetId is a valid Case ID
            if (!targetId.startsWith('500')) {
                return new Messaging.ActionResult.Builder()
                    .withSuccess(false)
                    .withMessage('Target ID must be a valid Case ID')
                    .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
                    .build();
            }
            
            switch on actionIdentifier {
                when 'reassignToQueue' {
                    return reassignCaseToQueue(targetId);
                }
                when else {
                    return new Messaging.ActionResult.Builder()
                        .withSuccess(false)
                        .withMessage('Unsupported action identifier: ' + actionIdentifier)
                        .withErrorCode(Messaging.ActionError.ACTION_NOT_IMPLEMENTED)
                        .build();
                }
            }
        } catch (Exception e) {
            return new Messaging.ActionResult.Builder()
                .withSuccess(false)
                .withMessage('An unexpected error occurred: ' + e.getMessage())
                .withErrorCode(Messaging.ActionError.INTERNAL_ERROR)
                .build();
        }
    }
    
    private Messaging.ActionResult reassignCaseToQueue(String caseId) {
        try {
            // Query the case to ensure it exists
            List<Case> cases = [SELECT Id, CaseNumber, OwnerId FROM Case WHERE Id = :caseId LIMIT 1];
            
            if (cases.isEmpty()) {
                return new Messaging.ActionResult.Builder()
                    .withSuccess(false)
                    .withMessage('Case not found with ID: ' + caseId)
                    .withErrorCode(Messaging.ActionError.INVALID_ACTION_PARAMETERS)
                    .build();
            }
            
            Case caseToUpdate = cases[0];
            
            // Query for the queue to assign the case to
            List<Group> queues = [SELECT Id, Name FROM Group WHERE Type = 'Queue' AND DeveloperName = :DEFAULT_QUEUE_NAME LIMIT 1];
            
            if (queues.isEmpty()) {
                return new Messaging.ActionResult.Builder()
                    .withSuccess(false)
                    .withMessage('Queue not found: ' + DEFAULT_QUEUE_NAME)
                    .withErrorCode(Messaging.ActionError.INVALID_STATE)
                    .build();
            }
            
            // Assign the case to the queue
            caseToUpdate.OwnerId = queues[0].Id;
            update caseToUpdate;
            
            return new Messaging.ActionResult.Builder()
                .withSuccess(true)
                .withMessage('Case ' + caseToUpdate.CaseNumber + ' successfully assigned to queue: ' + DEFAULT_QUEUE_NAME)
                .build();
                
        } catch (DmlException e) {
            return new Messaging.ActionResult.Builder()
                .withSuccess(false)
                .withMessage('Failed to update case: ' + e.getMessage())
                .withErrorCode(Messaging.ActionError.ACCESS_DENIED)
                .build();
        } catch (Exception e) {
            return new Messaging.ActionResult.Builder()
                .withSuccess(false)
                .withMessage('Error reassigning case to queue: ' + e.getMessage())
                .withErrorCode(Messaging.ActionError.INTERNAL_ERROR)
                .build();
        }
    }
}

The following example tests the implementation:

@IsTest
global class TestNotificationActionHandler {
    @IsTest
    static void testActionHandler() {

        //Set up the data, for example creating a case
        Case newCase = new Case(
            Subject = 'Important Case',
            Status = 'New',
            Priority = 'High'
        );
        insert newCase;

        //Set up Actionable Notification data
        Messaging.ActionableNotification notification =
            new Messaging.ActionableNotification.Builder()
                .withNotificationTypeId('0MLXXXXXXXXXXXX4AC')
                .withActionIdentifier('testAction')
                .withRecipientId(UserInfo.getUserId())
                .withSenderId(UserInfo.getUserId())
                .withTargetId(newCase.Id)
                .withTargetPageRef('/lightning/r/Case/' + newCase.Id + '/view')
                .build();


        Messaging.ActionResult result = Test.testNotificationActionHandler(new CaseNotificationActionHandler(), notification);

        //Insert assert statements here to verify your action
    }
}