Use Apex to Create an Asynchronous Callout to an External Service

When you register a schema containing a callback, External Services creates an invocable Apex operation with an automatically generated Apex class. Salesforce creates a callback URL on the asynchronous callout (initial callout) that’s read-only. Create an Apex client that’s capable of handling the callback by using the generated Apex interfaces. The client waits for an asynchronous response from the external system for an extended time (up to twenty-four hours).

Important
Important Connected apps creation is restricted as of Spring ‘26. You can continue to use existing connected apps during and after Spring ‘26. However, we recommend using external client apps instead. If you must continue creating connected apps, contact Salesforce Support.

See New connected apps can no longer be created in Spring ‘26 for more details.

Here’s some prerequisite reading and configuration to do before you create your own asynchronous callout.

As a comparison, a synchronous callout typically looks like this:

ExternalService.AcmeMortgages acme = new ...();

ExternalService.AcmeMortgages.GetApplication_Request request = new ...();
request.applicationNumber = 'X202290';

ExternalService.AcmeMorgages.GetApplication_Response response = 
    acme.GetApplication(request);

ExternalService.AcmeMortgages_MortgageApplication application = response.Code200;

To invoke an asynchronous callout, you must write your own Apex code to make the callout. Then, you must implement your own callback object and pass it into your asynchronous invocation method within your Apex code.

The callback handler must be stateless. Salesforce doesn't preserve state information when the response is called back.

Don't nest the callback class. The callback class should implement the callback interface directly. For example:

  • Correct: class MyCallback extends ES.ServiceName.OperationName_Callback {...}
  • Not Recommended: class SomeIntermediateClass extends ES.ServiceName.OperationName_Callback {...} and then MyCallback extends SomeIntermediateClass {...}
  1. From Setup, in the Quick Find box, enter Apex Classes in the Quick Find box, and then select Apex Classes.
  2. Find the Apex class that contains the callback interface you want to use.
  3. Create a callback. Write an Apex callback object that implements the External Services generated callback interface by referencing the corresponding Apex class.
  4. After you have a callback definition, pass this callback into your asynchronous invocation method within your Apex code.
Example
Example
// The callback gets called with the mortgage application update
// and handles each outcome, for example application is approved, rejected, ...
global class MyMortgageApplicationCallback extends ExternalService.AcmeMortgage.SubmitApplication_Callback {
    // Application approved
    global override void applicationOutcomeApproved(
            List<ExternalService.AcmeMortgages.SubmitApplication_applicationOutcomeApproved_Callback> callbacks) {
        ExternalService.AcmeMortgages.SubmitApplication_applicationOutcomeApproved_Callback callback = callbacks.get(0);
        if (callback.callbackStatus == CallbackStatus.COMPLETED) {
            Double loanAmount = callback.response.body.approvedAmount;
            // Create a Contact based on the response ...
        }            
    }
    
    // Application rejected
    global override void applicationOutcomeRejected(...) {...}
    
    ...
}

public class MyMortgageApplicationProcess {
    public void submitApplication(...) {
        // Submit mortgage application process
        ExternalService.AcmeMortgages acme = new ...();

        ExternalService.AcmeMortgages.SubmitApplication_Request request = new ...();
        ExternalService.AcmeMortgages_Contact applicant = new ...();
        applicant.Name = 'Joe Miller';
        applicant.Address = '555 Miller St, CA, Milltown';
        request.applicant = applicant;

        // Time out if no response after 1 day
        DateTime timeout = DateTime.now().addDays(1);

        ExternalService.AcmeMorgages.SubmitApplication_Response response = 
        acme.SubmitApplication(request, new MyMortgageApplicationCallback(), timeout);
    
        // Get back application number immediately
        String appNr = response.Code201.applicationNumber;

        // Get invocationId from a successful initial response to check status of the background operation
        String invocationId = response.invocationId;
        ...
    }
}