AI generated image of dogs going into a machine and turning into rabbits

Invocable Methods Made Easier: A Better Way to Send Data Between Flow and Apex

Here is the simplest way I have seen to use invocable methods to send data from flow to apex and apex to flow. This is a huge improvement over what I wrote in 2021.

The trickiest thing to understand here is that an output variable in Flow is an INPUT variable in Apex. It goes OUT from the Flow and IN to your Apex. I have some charts to help clarify what goes in and what comes out.

Some caveats: These are not examples of when to use Flow and Apex together, but just how it can be done. Also, I am a newer developer and I am just figuring this stuff out. If you see ways to improve, let me know!

Thanks to @jonsayer for showing me this method while working on the latest Unsubscribe Link (coming soon)!

EXAMPLE ONE

Get an Account Id, send it as a text variable from the Flow to Apex, return all the opportunities on that account to the flow, and update them in the Flow.

public with sharing class mostBasicClass {
  @InvocableMethod(
    label='Test Sending one Variable'
    description='test sending and receiving with Flow'
  )
  public static List<FlowOutputs> receiveInput(List<FlowInputs> input) {
    List<FlowOutputs> results = new List<FlowOutputs>();
    for (FlowInputs i : input) {
      FlowOutputs theOutputs = new FlowOutputs();
      theOutputs.var_Output = myMethod(i.var_Input);
      results.add(theOutputs);
    }
    return results;
  }

  public static List<Opportunity> myMethod(String var_Input) {
    List<Opportunity> var_Output = [
      SELECT Id
      FROM Opportunity
      WHERE AccountId = :var_Input_AccountId
    ];
    return var_Output;
  }

  //input variables that come to apex from flow
  public class FlowInputs {
    @InvocableVariable
    public String var_Input;
  }

  //output variables that go from Apex to flow
  public class FlowOutputs {
    @InvocableVariable
    public List<Opportunity> var_Output;
  }
}

The two charts below explain how each variable is classified in both Flow and Apex. Flow variables are designated as as Available for Input or Available for Output when creating them.

Send AccountID from Flow to Apex

DirectionVariable NameVariable Format
FlowOutputvar_texttext
ApexInputvar_InputString

Send Opportunities from Apex to Flow

DirectionVariable NameVariable Format
FlowInputincomingOppsListrecord collection variable (opportunities)
ApexOutputvar_OutputList of opportunities

Add an action to the canvas and find your invocable method. Assign the Flow variables to the Apex variables. Variables coming IN to the flow need to be assigned under advanced options.

Prompt for the AI: dogs as input and bunnies as output

EXAMPLE TWO

Send a single opportunity record and a collection of opportunities to Apex. Return an integer and a list of Opportunities to update in Flow. There are three versions of the code below – 1 bare bones, 2 with comments, 3 with an example instead of //do the thing.

Send Opportunity Record From Flow to Apex

DirectionVariable NameVariable Format
FlowOutputOpportunity from get opprecord variable
ApexInputrec_ToApexOppOpportunity

Send Record Collection From Flow to Apex

DirectionVariable NameVariable Format
FlowOutputOpportunities from get Opportunitiesrecord collection variable
ApexInputlist_toApexOppsList of Opportunities

Send Integer from Apex to Flow

DirectionVariable NameVariable Format
FlowInputvar_NumberOfOppsNumber
ApexOutputinto_ToFlowInteger

Send Opportunity List from Apex to Flow

DirectionVariable NameVariable Format
FlowInputincomingOppsListrecord collection variable
ApexOutputlist_ToFlowOppsList of Opportunities
The concept of one input (dog) turning into a different output (rabbit) is hard to explain to AI.

EXAMPLE TWO WITHOUT COMMENTS

public class sampleApexClass {
  public static Integer numberOfOpportunities;

  @InvocableMethod(
    label='Test Sending Variables'
    description='test sending and receiving with Flow'
  )
  public static List<FlowOutputs> receiveInput(List<FlowInputs> input) {
    List<FlowOutputs> results = new List<FlowOutputs>();
    for (FlowInputs i : input) {
      FlowOutputs theOutputs = new FlowOutputs();
      theOutputs.list_toFlowOpps = dotheThing(
        i.rec_toApexOpp,
        i.list_toApexOpps
      );
      theOutputs.int_toFlow = numberOfOpportunities;

      results.add(theOutputs);
    }
    return results;
  }

  public static List<Opportunity> doTheThing(
    Opportunity rec_toApexOpp,
    List<Opportunity> list_toApexOpps
  ) 
//do something
…
    return list_toFlowOpps;
  }

  //input details that comes to apex from flow
  public class FlowInputs {
    @InvocableVariable
    public Opportunity rec_toApexOpp;
    @InvocableVariable
    public List<Opportunity> list_toApexOpps;
  }

  //output details that go from Apex to flow
  public class FlowOutputs {
    @InvocableVariable
    public List<Opportunity> list_toFlowOpps;
    @InvocableVariable
    public Integer int_toFlow;
  }
}

EXAMPLE TWO WITH COMMENTS

public class sampleApexClass {
  //optional: a class variable to hold the integer I will return to the Flow.
  public static Integer numberOfOpportunities;
  //declare the invocable method.
  @InvocableMethod(
    label='Test Sending Variables'
    description='test sending and receiving with Flow'
  )
  //this method will receive a list of flowinputs and return a list of flowoutputs
  public static List<FlowOutputs> receiveInput(List<FlowInputs> input) {
    List<FlowOutputs> results = new List<FlowOutputs>();
    for (FlowInputs i : input) {
      FlowOutputs theOutputs = new FlowOutputs();
      //from here you start adding your outputs
      //theOutputs dot one of your output variables (list_toFlowOpps)
      //here my list = the list returned from the doTheThing method

      theOutputs.list_toFlowOpps = dotheThing(
        //I pass the inputs to the method
        i.rec_toApexOpp,
        i.list_toApexOpps
      );
      //for my next output, I can set its value directly here
      theOutputs.int_toFlow = numberOfOpportunities;
      
      results.add(theOutputs);
    }
    return results;
  }

  public static List<Opportunity> doTheThing(
    Opportunity rec_toApexOpp,
    List<Opportunity> list_toApexOpps
  ) {
    //use the variables to do something
    ...
    numberOfOpportunities = list_toFlowOpps.size();
    return list_toFlowOpps;
  }

  //list each flowinput with @InvocableVariable above it
  public class FlowInputs {
    @InvocableVariable
    public Opportunity rec_toApexOpp;
    @InvocableVariable
    public List<Opportunity> list_toApexOpps;
  }

  //list each flowOutput with @InvocableVariable above it
  public class FlowOutputs {
    @InvocableVariable
    public List<Opportunity> list_toFlowOpps;
    @InvocableVariable
    public Integer int_toFlow;
  }
}
A dog goes from Flow to Apex and the output is a fuzzy bunny with a fuzzy horn? Image by WordPress AI.

EXAMPLE TWO – COMMENTS, FULLY WORKING CODE

public class sampleApexClass {
  //optional:a class variable to hold the integer I will return to the Flow.
  public static Integer numberOfOpportunities;
  //declare the invocable method.
  @InvocableMethod(
    label='Test Sending Variables'
    description='test sending and receiving with Flow'
  )
  //this method will receive a list of flowinputs and return a list of flowoutputs
  public static List<FlowOutputs> receiveInput(List<FlowInputs> input) {
    List<FlowOutputs> results = new List<FlowOutputs>();
    for (FlowInputs i : input) {
      FlowOutputs theOutputs = new FlowOutputs();
      //from here you start adding your outputs
      //theOutputs dot one of your output variables (list_toFlowOpps)
      //here my list = the list returned from the doTheThing method

      theOutputs.list_toFlowOpps = dotheThing(
        //I pass the inputs to the method
        i.rec_toApexOpp,
        i.list_toApexOpps
      );
      //for my next output, I can set its value directly here
      theOutputs.int_toFlow = numberOfOpportunities;

      results.add(theOutputs);
    }
    return results;
  }
/*here I take the list of opportunities from the flow, loop through them and change the close date based on the Opportunity record from the flow.I do not update the records here, but send them back to the flow. */

  public static List<Opportunity> doTheThing(
    Opportunity rec_toApexOpp,
    List<Opportunity> list_toApexOpps
  ) {
    //use the variables to do something
    List<Opportunity> list_toFlowOpps = new List<Opportunity>();
    for (Opportunity loopOpp : list_toApexOpps) {
      if (loopOpp.CloseDate < rec_toApexOpp.CloseDate) {
        loopOpp.CloseDate = rec_toApexOpp.CloseDate;
      }
      list_toFlowOpps.add(loopOpp);
    }
    numberOfOpportunities = list_toFlowOpps.size();
    return list_toFlowOpps;
  }

  //list each flowinput with @InvocableVariable above it
  public class FlowInputs {
    @InvocableVariable
    public Opportunity rec_toApexOpp;
    @InvocableVariable
    public List<Opportunity> list_toApexOpps;
  }

  //list each flowOutput with @InvocableVariable above it
  public class FlowOutputs {
    @InvocableVariable
    public List<Opportunity> list_toFlowOpps;
    @InvocableVariable
    public Integer int_toFlow;
  }
}

I hope this is helpful to you! What other examples would you like to see?

Published by

JessieRymph

Jessie joined Salesforce.org in 2018 to give introductory webinars to nonprofit customers. She now is a Senior Solution Developer supporting nonprofits and education customers at Salesforce. All opinions expressed on this blog are her own or those of the contributors. She's spent 17 years more or less in CRMs and databases, but didn't meet Salesforce until 2011. Jessie co-led the Seattle Salesforce Nonprofit User Group in 2015-2016. She wrote a sh*tty first draft of a novel and hopes to turn it into a screenplay!

One thought on “Invocable Methods Made Easier: A Better Way to Send Data Between Flow and Apex”

Leave a Reply