You are here:
Let Flows Execute Apex Actions
Flow Builder comes with much functionality, but sometimes your flow must do more than the default elements allow. 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.
@InvocableMethod
annotation instead of the Process.Plugin
interface.Process.Plugin Interface |
@InvocableMethod Annotation |
|
|---|---|---|
| Apex data type support | Doesn’t support:
|
Doesn’t support:
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 |
| 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:
|
| More Details in Apex Developer Guide |
Passing Data to a Flow Using the Process.Plugin Interface
|
InvocableMethod Annotation and InvocableVariable Annotation |
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;
}
}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.

