Custom Hooks for Template Operation

All five Sales Config Template APIs support Pre and Post invoke hooks via the standard CpqAppHandlerHook framework. This allows you to inject custom Apex logic before and after each template operation without any platform code changes.

Required Editions

Available in: Classic and Lightning Experience
Available in: Enterprise, Unlimited, and Developer Editions for CME Managed Package

Hook Keys

Hooks are identified by the pattern {methodName}.PreInvoke and {methodName}.PostInvoke:

API Pre Hook Key Post Hook Key
Save Template saveSalesConfigTemplate.PreInvoke saveSalesConfigTemplate.PostInvoke
Get Template getSalesConfigTemplate.PreInvoke getSalesConfigTemplate.PostInvoke
Search Templates searchSalesConfigTemplate.PreInvoke searchSalesConfigTemplate.PostInvoke
Apply Template applySalesConfigTemplate.PreInvoke applySalesConfigTemplate.PostInvoke
Delete Template deleteSalesConfigTemplate.PreInvoke deleteSalesConfigTemplate.PostInvoke

Hook Lifecycle

For every operation, execution occurs in this order:

  • {methodName}.PreInvoke - runs before the core operation
  • Core operation - Save / Get / Search / Apply / Delete logic
  • {methodName}.PostInvoke - runs after output is fully populated

Implementation Script

Create an Apex class named CPQAppHandlerHookImplementation (outside the managed package) that implements either VlocityOpenInterface or VlocityOpenInterface2. The platform's CpqAppHandlerHookImplementation will automatically discover and delegate to it. Here is the same code for a hook on Save Template:

public class CPQAppHandlerHookImplementation implements
        VlocityOpenInterface {                                                        
        
        public Boolean invokeMethod(String methodName, Map<String, Object>  
        input,          
        Map<String, Object> output,             
        Map<String, Object> options) {                                          
        
        if (methodName == 'saveSalesConfigTemplate.PostInvoke') {             
        onSaveTemplatePost(input, output);
        } else if (methodName == 'applySalesConfigTemplate.PreInvoke') {      
        onApplyTemplatePre(input);                                        
        }                                                                     
        return true;                                                          
        }                                                                         
        
        private void onSaveTemplatePost(Map<String, Object> input,          
        Map<String, Object> output) {
        // Custom logic after a template is saved                             
        // output contains: result.records[0].templateId, success, errorCode  
        }                                                                         
        
        private void onApplyTemplatePre(Map<String, Object> input) {        
        // Custom logic before a template is applied
        // input contains: templateId, cartId, name, asyncMode, pricing,      
        validation                                                                    
        }                                                                         
        }

Message Structure

Each message in the messages array contains:

{                                                            
        "code": "TEMPLATE_NOT_FOUND",                                               
        "severity": "ERROR",                                                        
        "message": "Template with ID 'a1Bxx0000004XyzDEF' not found"                
        }
Field Type Value Description
code String Varies A machine-readable error code.
severity String ERROR, WARN, INFO The severity level of the message.
message String Varies A human-readable description of the error or warning.