Apex Hooks in Salesforce Revenue Cloud

Photo of author
Written By Jean-Michel Tremblay
Salesforce Consultant

Salesforce Revenue Cloud’s Summer ’25 release introduces a powerful new feature: Apex Hooks for Pricing Procedures. This is a game-changer for anyone needing to implement complex pricing logic, pass attribute values seamlessly, or integrate external data into their pricing calculations. Say goodbye to many previous limitations and hello to a new era of flexibility!

What Are Pricing Procedure Hooks?

In essence, pricing procedure hooks are custom Apex code snippets that you can execute at specific points during the pricing process. You have two main options:

  • Prehooks: These Apex classes run before your standard pricing procedure kicks in. This is ideal for preparing data, performing initial calculations, or fetching external information that your pricing rules will depend on.
  • Posthooks: These execute after your pricing procedure has completed. Use these to make final adjustments, update related records, or concatenate information for display purposes.

The beauty of this is the full power of Apex at your fingertips. You can interact with Sales Transaction Items (like Quote Lines or Order Lines) and their attributes, perform complex calculations, modify data in the transaction context, and even (with careful consideration for performance) make callouts to external systems.

Why Are Apex Hooks a Big Deal?

Previously, certain complex pricing scenarios were challenging or impossible to implement directly within the standard pricing procedure framework. Apex Hooks now bridge that gap by allowing you to:

  • Calculate Complex Formulas: Implement intricate business logic that goes beyond standard rule capabilities.
  • Pass Attribute Values to Lines: Easily transfer attribute selections made during configuration directly to fields on the corresponding quote or order lines.
  • Integrate External Data: Fetch real-time data from other Salesforce objects or even external systems to influence pricing.
  • Dynamic Updates: Modify data within the transaction context before or after the main pricing logic runs, ensuring accurate and dynamic results.
  • Bundle Power: Maintain parent-child relationships within your code, allowing you to apply logic or carry attribute values down to product options (components) within a bundle.

How to Implement Pricing Procedure Hooks: A Step-by-Step Guide

Let’s walk through the process of setting up and using Apex Hooks in your Revenue Cloud environment (Summer ’25 or later).

Step 1: Enable Procedure Plan Orchestration and Exclude Default Procedures

First, you need to configure Revenue Cloud to utilize the new procedure plan framework for pricing:

  1. Navigate to Setup > Revenue Settings.
  2. Locate the Procedure Plan Orchestration for Pricing setting.
    • Enable this setting. The description states: “Make pricing more efficient by enabling Salesforce to calculate pricing using procedure plans.”
  3. Next, find the setting Exclude Default and Sales Transaction Type Pricing Procedures.
    • Enable this setting as well. The description explains: “When calculating pricing, exclude the default pricing procedure and any pricing procedure set for the sales transaction type of a quote or order. By excluding these pricing procedures, Salesforce will use only the pricing procedures specified in the procedure plan to calculate the pricing.”

By enabling both of these settings, you ensure that your custom Procedure Plans, along with any Apex Hooks they contain, will be the definitive source for pricing logic execution.

Step 2: Create Your Apex Class(es)

This is where your custom logic resides. You’ll need at least one Apex class (or two if you’re using both pre and post hooks).

Key Requirement: Your Apex class must implement the RevSignaling.SignalingApexProcessor interface. This interface has a single method, execute, which will contain your logic.


    // Basic structure of an Apex Hook class
    global class MyPricingPreHook implements RevSignaling.SignalingApexProcessor {
        public RevSignaling.TransactionResponse execute(RevSignaling.TransactionRequest request) {
            // Your pre-pricing logic here
            // Access contextId: request.ctxInstanceId
            // Use Context.IndustriesContext for querying and updating

            RevSignaling.TransactionResponse response = new RevSignaling.TransactionResponse();
            // Set response.status (SUCCESS or FAILED) and response.message
            // Example:
            // response.status = RevSignaling.TransactionStatus.SUCCESS;
            // response.message = 'Pre-hook executed successfully.';
            return response;
        }
    }
    

Within the execute method, you’ll use Context.IndustriesContext to query for SalesTransactionItem and SalesTransactionItemAttribute nodes based on the contextId from the TransactionRequest. You can then prepare and submit updates using industriesContext.updateContextAttributes().

Step 3: Create a Procedure Plan Definition

Procedure Plans orchestrate the steps in your pricing process.

  1. In Setup, search for “Procedure Plan Definitions” and click New.
  2. Set the following:
    • Process Type: Revenue Cloud
    • Object: Quote (or Order, or Both, depending on your needs)
    • Context Definition: Select the active pricing procedure context definition you want this plan to use.
  3. Save your Procedure Plan Definition.

Step 4: Define Procedure Plan Sections

This is where you link your Apex classes and your standard pricing procedure.

  1. In your newly created Procedure Plan Definition, navigate to the “Procedure Plan Sections” related list.
  2. Click New for each section you need to add. You’ll typically create sections in this order:
  3. Pre-Hook Section (Optional):
    • Enter a Section Name (e.g., “Pre-Pricing Apex Hook”).
    • Section Type: Apex
    • Apex Class: Select the Apex class you created for your pre-hook logic.
    • Set the Order to determine its execution sequence (e.g., 10 for the first step).
  4. Pricing Procedure Section:
    • Enter a Section Name (e.g., “Main Pricing Procedure”).
    • Section Type: Pricing Procedure
    • Pricing Procedure: Link to your existing pricing procedure that contains your standard pricing rules.
    • Set the Order to run after the pre-hook (if used) (e.g., 20).
  5. Post-Hook Section (Optional):
    • Enter a Section Name (e.g., “Post-Pricing Apex Hook”).
    • Section Type: Apex
    • Apex Class: Select the Apex class you created for your post-hook logic.
    • Set the Order to run last (e.g., 30).
  6. Save each section.
  7. Finally, ensure your main Procedure Plan Definition is marked as Active.

Best Practices for Your Apex Hook Classes

Writing robust and efficient Apex is crucial, especially in a process as critical as pricing.

Validate Line/Attribute Status (Not Deleted):

Selective Querying: Only query the tags ('SalesTransactionItemAttribute', 'SalesTransactionItem') and attributes you absolutely need. The context can contain a lot of data; being specific improves performance. Filter attributes within your Apex logic after querying the main tags.

Null Checks and Graceful Error Handling: Always check for null values when accessing map keys, attribute values, or elements from lists (e.g., dataPath elements). Implement robust try-catch blocks around major logic sections, especially the context update call. Use the TransactionResponse to signal success or failure clearly.

Understand Data Paths (dataPath): The dataPath is crucial for targeting updates to the correct nodes.

Parent-Child Relationships & Attribute Propagation: When dealing with bundles, the LineItemPath tag on SalesTransactionItem is key. It often contains a path like ParentQLI_ID/ChildQLI_ID. The examples cleverly use this to determine the “source” QLI from which to fetch attribute values, ensuring that child/option lines can inherit or use values from their parent bundle.
            String currentLineItemPathValue = (String)((Map<String, Object>)currentSalesItemTags.get('LineItemPath')).get('tagValue');
String attrSourceQliId;
if (currentLineItemPathValue != null && currentLineItemPathValue.contains('/')) {
attrSourceQliId = currentLineItemPathValue.split('/')[0]; // Get the parent/source QLI
} else {
attrSourceQliId = actualQliOrRefOfCurrentItem; // It's a parent or standalone item
}
Map<String, String> effectiveOrigAttrValues = qliToSourceAttributeValues.get(attrSourceQliId);
  • Performance for Callouts: While callouts are technically possible if the Apex class is not directly part of the pricing transaction save (consult Salesforce documentation on transaction boundaries for hooks), be extremely mindful of their performance impact. Pricing calculations are often synchronous and user-facing. Long-running callouts can lead to poor user experience or even hit governor limits. If callouts are necessary:
    • Ensure they are quick and optimized.
    • Set appropriate timeouts.
    • Test thoroughly under load.
    • Consider using Platform Events or other asynchronous mechanisms for updates that don't need to be strictly real-time within the pricing calculation if callouts are lengthy. The provided example PDF shows callouts but always test performance implications.
  • Constants for Attribute Names and Magic Strings: Use private static final variables for API names of fields (e.g., PayloadCapacityRequirement__c), attribute names used in the context (e.g., 'Payload_Capacity_Requirement'), and any other fixed strings. This reduces typos and makes code maintenance significantly easier. The examples correctly use this pattern (e.g., INPUT_ATTRIBUTES_FOR_CALC_AND_MAPPING, DESCRIPTION_FIELD_API_NAME).
  • Code Readability and Modularity: Break down complex logic into smaller, well-named private methods if your execute method becomes too long. Comment your code clearly, explaining the "why" behind logic, especially for complex transformations or data path manipulations.

Example Scenarios in Action

Based on the video walkthrough and provided code, here are a couple of practical examples:

  • Pre-hook Example: Dynamic Calculation & Attribute Mapping (ApexPreHookPayloadCapacity)
    • Dynamically calculates the "MaxPayload" attribute value based on several other input attributes (Payload_Capacity_Requirement, TerrainAdaptationLevel, MobilityType) using predefined factors in Apex Maps.
    • Updates the "MaxPayload" SalesTransactionItemAttribute node in the context.
    • Maps the values of source attributes (like 'Operating_Mode', 'Payload_Capacity_Requirement') and the newly calculated "MaxPayload" to corresponding custom fields on the SalesTransactionItem (e.g., Quote Line's OperatingMode__c, MaxPayload__c).
    • Correctly handles bundled products by ensuring that child/option lines receive the attribute values and calculated MaxPayload derived from their parent bundle.
    • Includes a check to skip processing for lines marked as 'DELETED'.
  • Post-hook Example: Concatenating a Description (ApexPostHookUpdateDescription)
    • After all pricing is calculated by the main pricing procedure, this hook runs.
    • It queries the SalesTransactionItemAttribute nodes again to get the final values of specified attributes for each line (including 'MaxPayload', which might have been calculated by a pre-hook and further adjusted by pricing).
    • Concatenates these attribute values into a single, comprehensive description string, separated by " - ".
    • Updates a specified description field (e.g., SalesTrxnItemDescription) on the SalesTransactionItem (Quote Line) with this new concatenated string.
    • Also uses the LineItemPath to correctly source attribute values for parent and child items.

Access the full code examples here : Apex Class for Prehook and Posthook examples

Looking Ahead

Apex Hooks in Revenue Cloud pricing procedures open up a vast array of possibilities for tailoring the pricing engine to meet even the most unique business requirements.

By understanding how to set them up and following best practices in your Apex development, you can significantly enhance the power and flexibility of your Salesforce Revenue Cloud implementation.

If you have questions or need assistance implementing Apex Hooks in your environment, don't hesitate to reach out!

Leave a Comment