Loading
Automate Your Business Processes
Table of Contents
Select Filters

          No results
          No results
          Here are some search tips

          Check the spelling of your keywords.
          Use more general search terms.
          Select fewer filters to broaden your search.

          Search all of Salesforce Help
          Let Flows Execute Apex Actions

          Let Flows Execute Apex Actions

          Flow Builder provides many capabilities, but sometimes your flow requires functionality beyond the default elements. In that case, call an Apex class from your flow by using an Apex action.

          Required Editions

          View supported editions.

          Developers have two options when they’re trying to make an Apex class available as an Action element for a flow. While the Process.Plugin interface supports customizing how the class appears in the palette, the @InvocableMethod annotation provides more functionality. The following table describes the features supported by each option.

          Tip
          Tip We recommend using the @InvocableMethod annotation instead of the Process.Plugin interface.
          Important
          Important Legacy Apex actions aren’t supported in auto-layout in Flow Builder. Legacy Apex actions are only available to be added in free-form in Flow Builder. Existing actions can be edited in both auto-layout and free-form mode.
            Process.Plugin Interface @InvocableMethod Annotation
          Apex data type support

          Doesn’t support:

          • Blob
          • Collection
          • sObject
          • Time

          Doesn’t support:

          • Generic Object
          • Sets
          • Maps
          • Enums

          Flow Builder doesn’t support mapping an Apex method’s input or output parameters to a record collection variable.

          Bulk operations Not supported Supported
          Custom icons Not supported Supported
          Element type in Flow Builder Action Action
          Customizable configuration experience Not supported Supported through InvocableActionExtension metadata. Developers can customize input order and grouping, add custom headers, define picklists for inputs, and create custom property editors for specific input parameters.
          Element name in Flow Builder Class name or the value of the name property. Class name
          Reusability Classes with this interface implemented are available in flows

          Classes with this annotation implemented are available in:

          • Flows
          • Processes
          • Rest API
          More Details in Apex Developer Guide Passing Data to a Flow Using the Process.Plugin Interface InvocableMethod Annotation and InvocableVariable Annotation
          Example
          Example To illustrate the difference between these two implementation methods, here are two classes that do the same thing: get an account name from a flow and return that account’s ID.

          This class implements the @InvocableMethod annotation.

          global class lookUpAccountAnnotation {
             @InvocableMethod
             public static List<String> getAccountIds(List<String> names) {
                List<Id> accountIds = new List<Id>();
                List<Account> accounts = [SELECT Id FROM Account WHERE Name in :names];
                for (Account account : accounts) {
                   accountIds.add(account.Id);
                }
                return accountIds;
             }
          }
          Note
          Note

          To invoke Apex from a flow, the running user requires the corresponding Apex class assignment in their profile or permission set.

          Note
          Note

          Starting in API version 66.0, custom Apex classes used as invocable action parameters require an accessible no-argument constructor. For more information, see "Spring '26 (API Version 66.0)" under Versioned Updates.

          This class implements the Process.Plugin interface.

          global class lookUpAccountPlugin implements Process.Plugin { 
          
             global Process.PluginResult invoke(Process.PluginRequest request) { 
                String name = (String) request.inputParameters.get('name');
                Account account = [SELECT Id FROM Account WHERE Name = :name LIMIT 1][0];
          
                Map<String,Object> result = new Map<String,Object>();
                result.put('accountId', account.Id);
                return new Process.PluginResult(result);
             }
          
             global Process.PluginDescribeResult describe() { 
                Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
                result.Name = 'Look Up Account ID By Name';
                result.Tag = 'Account Classes';
                result.inputParameters = new 
                   List<Process.PluginDescribeResult.InputParameter>{ 
                      new Process.PluginDescribeResult.InputParameter('name', 
                      Process.PluginDescribeResult.ParameterType.STRING, true) 
                   }; 
                result.outputParameters = new 
                   List<Process.PluginDescribeResult.OutputParameter>{              
                      new Process.PluginDescribeResult.OutputParameter('accountId', 
                      Process.PluginDescribeResult.ParameterType.STRING)
                          }; 
                return result; 
             }
          }

          Notice that lookupAccountAnnotation is less than half the length (11 lines) of lookupAccountPlugin (28 lines). In addition, because the annotation supports bulk operations, lookupAccountAnnotation performs one query per batch of interviews. lookupAccountPlugin performs one query per interview.

           
          Loading
          Salesforce Help | Article