Developers / Admins

Salesforce Invocable Apex Methods: A Complete Breakdown

By Atlas Can

Developers and admins are great, but what if they join their forces? As you already know, Apex is Salesforce’s backend programming language and is a powerful tool for customizing and extending the functionality of your Salesforce org. One of the most useful features of Apex is the ability to create invocable methods that can be called declaratively by tools like Process Builder, Flow Builder, and even external systems via the REST API.

In this article, we’ll take a deep dive into invocable Apex methods. We’ll explain what they are, how they work, and provide real-world business scenarios and code samples to illustrate their usefulness. By the end, you’ll have a solid understanding of when and how to leverage invocable Apex to supercharge your own Salesforce org.

Invocable Apex Explained

So what exactly makes an Apex method “invocable”? In short, it’s a method that is specifically designed to be called by a declarative tool or external system. To make a method invocable, you simply annotate it with @InvocableMethod and ensure it meets a few key requirements.

The method must be static and public. It must have at least one input parameter of a supported type (primitives, collections, SObjects, etc.)

If it has an output, it must be a supported type, and the method must return that type.

Here’s a simple example of an invocable method that takes in a list of account IDs and returns a list of the corresponding account names:

public class AccountUtility {
    @InvocableMethod(label='Get Account Names')
    public static List<String> getAccountNames(List<ID> accountIds) {
        List<String> accountNames = new List<String>();
        for (Account acct : [SELECT Name FROM Account WHERE Id IN :accountIds]) {
            accountNames.add(acct.Name);
        }
        return accountNames;
    }
}

Once defined, this method could be called by a process or flow simply by referencing the Apex class and method name. The real power comes in being able to combine complex Apex logic with the ease and flexibility of declarative tools.

There are a few key considerations and limits to keep in mind when working with invocable methods:

  • They can take a maximum of one input argument (although that argument can be a collection).
  • They can return a single value or a single list of values.
  • They are subject to the same governor limits as other Apex code.
  • They cannot be used in SOQL queries, DML operations, or approval processes.

With those basics in mind, let’s look at some real-world scenarios where invocable methods can be extremely useful.

A common business requirement is to automatically update certain fields on related records when a “parent” record changes. For example, let’s say we want to mark all open tasks as complete when an opportunity is “Closed Won”.

We could achieve this with an invocable method like:

public class OpportunityUtility {
    @InvocableMethod(label='Complete Open Tasks')
    public static void completeOpenTasks(List<Id> opportunityIds) {
        List<Task> tasksToUpdate = [SELECT Id 
                                     FROM Task
                                     WHERE WhatId IN :opportunityIds
                                     AND Status NOT IN ('Completed', 'Closed')];

        for (Task task : tasksToUpdate) {
            task.Status = 'Completed';
        }

        update tasksToUpdate;
    }
}

This method takes in a list of Opportunity IDs, queries for any open tasks related to those opps, and updates their status to “Completed”.

We could then call this method from a process or flow that fires when an opportunity is “Closed Won”. The Process Builder configuration would look something like this:

  • Start the process when an opportunity is created or edited.
  • Add criteria to check if the Stage is equal to “Closed Won”.
  • Add an immediate action to call Apex, referencing the OpportunityUtility class and completeOpenTasks method, passing the Opportunity ID.

By combining the declarative process with the invocable Apex, we get the best of both worlds – the process provides the when, and Apex provides the how. This separation of concerns makes the solution more modular and easier to maintain.

Business Scenario: Custom Approval Processing

Another common use case for invocable methods is custom approval processing. While Salesforce provides standard approval processes, there are often scenarios that require more complex logic, such as multi-step approvals or approvals that need to interact with external systems.

Let’s consider a scenario where we need to submit a custom object called “Expense Report” for approval, and if approved, automatically create a related “Expense Payment” record and send an email to the submitter.

Our invocable method could look like this:

public class ExpenseReportUtility {
    @InvocableMethod(label='Process Expense Report Approval')
    public static void processExpenseReportApproval(List<Expense_Report__c> expenseReports) {
        List<Expense_Payment__c> paymentsToCreate = new List<Expense_Payment__c>();
        List<Messaging.Email> emailsToSend = new List<Messaging.Email>();

        for (Expense_Report__c er : expenseReports) {
            if (er.Status__c == 'Approved') {
                Expense_Payment__c payment = new Expense_Payment__c();
                payment.Amount__c = er.Total_Amount__c;
                payment.Expense_Report__c = er.Id;
                paymentsToCreate.add(payment);

                Messaging.SingleEmailMessage email = new Messaging.SingleEmailMessage();
                email.setToAddresses(new String[] { er.Submitted_By__r.Email });
                email.setSubject('Expense Report Approved');
                email.setPlainTextBody('Your expense report for ' + er.Total_Amount__c + ' has been approved.');
                emailsToSend.add(email);
            }
        }

        insert paymentsToCreate;
        Messaging.sendEmail(emailsToSend);
    }
}

This method takes in a list of Expense Report records. For each approved record, it creates a related Expense Payment and sends an email to the submitter.

We could call this method from a flow that is triggered when an Expense Report is submitted for approval. The flow could handle gathering the necessary approvals (perhaps via another invocable method) and then call the processExpenseReportApproval method to handle the post-approval actions.

By encapsulating the approval processing logic in an invocable method, we make it reusable across multiple processes or flows. We also keep our flow logic simpler and more focused on the approval-gathering steps.

Best Practices and Considerations

When deciding whether to use an invocable method, consider the following:

  • Is the logic reusable across multiple processes or flows?
  • Does the logic require complex calculations, queries, or external system integrations?
  • Do you need the flexibility to modify the logic independently from the process or flow?
  • If the answer to any of these is yes, an invocable method is likely a good choice.

When writing invocable methods, keep these best practices in mind:

  • Keep them focused on a single task or responsibility.
  • Use bulk processing (i.e. take in and return collections) whenever possible to avoid hitting governor limits.
  • Write unit tests to cover your invocable methods just like you would any other Apex code.
  • Consider edge cases and add error handling where appropriate.
  • Document your methods clearly, including expected inputs and outputs.

Remember, invocable methods are subject to the same governor limits as other Apex code, so be mindful of SOQL queries, DML statements, and CPU time limits.

Summary

Invocable Apex methods are a powerful tool for extending and customizing Salesforce functionality. By combining the declarative power of Process Builder and Flow with the flexibility and robustness of Apex, you can create solutions that are both easy to build and maintain.

The next time you find yourself writing complex validation rules, workflow field updates, or process builder formulas, consider whether an invocable method might be a better approach. You might just find that it makes your solution more readable, reusable, and robust.

We’ve only scratched the surface of what’s possible with invocable methods. For more information and examples, check out the Salesforce Developer Documentation on Invocable Apex. Happy coding!

The Author

Atlas Can

Atlas works as a 10x certified Salesforce Developer at Omnivo Digital and active on communities including his community SFDX.

Comments:

    Eric Smith
    April 04, 2024 2:18 pm
    Nice article. Here's a presentation from TrailblazerDX 2024 that touches on Invocable Actions for Flows. https://youtu.be/9pvrd8mOhGE?si=m5WSppho2rifPaqZ
    Frederick Lane
    April 05, 2024 7:33 am
    Great, concise article thanks Atlas. Given that Process Builder is being phased-out, would it not be better to advise only the most suitable alternatives? And would for the related records update example, Flow work well as a replacement for Process Builder?
    Atlas Can
    April 09, 2024 10:34 am
    Hi Frederick, great question! I recommend using Flows as much as possible. Process Builder can still be useful for simple automation scenarios but they should be used as last resort! Flows provide a more robust, flexible, and future-proof solution for complex business process automation in Salesforce.
    M L C
    August 07, 2024 10:32 am
    Only one parameter is supported on methods with @Invocable annotation

Leave a Reply