---
schema_version: "1"
id: 6bb8d7b7fb89e58cd0bc6bc0b8c37184ff4bada8d1253f059129eddf0bcc7da4
title: Custom Hooks for Template Operation
collection: admin
version: current
locale: en-us
portal_url: https://docs.salesforce.com/admin/current/en-us/ind/264-0-0/comms_cpq_custom_hooks_for_template_operation.md
canonical_url: https://help.salesforce.com/s/articleView?id=ind.comms_cpq_custom_hooks_for_template_operation.htm&release=264.0.0&type=5
source_site: help.salesforce.com
content_type: documentation
content_hash: 18161e9576b7f8eea58fc66ca6e1918144fa22018766e6af8380b8b2ffd97056
description: 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.
products:
  - Communications
  - Media
  - Energy and Utilities
release: "264"
---
# 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

<table class="slds-table slds-table_bordered slds-max-medium-table_stacked slds-m-bottom_small edition"><colgroup><col style="width:100%"></colgroup><tbody><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: Classic and Lightning Experience</td></tr><tr class=""><td class="slds-cell-wrap" style="vertical-align:top;">Available in: <strong>Enterprise</strong>, <strong>Unlimited</strong>, and <strong>Developer</strong> Editions for CME Managed Package</td></tr></tbody></table>

## 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. |

- **[Save Template Using OmniScript](https://help.salesforce.com/s/articleView?id=ind.comms_cpq_omniscript_for_save_template.htm&release=264.0.0&type=5)**  
    Use the pre-built OmniScript to save an existing Quote or Order as a reusable template from the CPQ Cart UI.