In this blog, we will explore how to make callouts in Apex in Salesforce and provide a detailed example of connecting two Salesforce orgs.
In the Salesforce development journey, we always encounter scenarios where we need to exchange data with an external system, so here we can do integration/callouts to connect the external system with our Salesforce org.
A callout in Apex is the process of connecting multiple systems. By using callouts, we can send data to or retrieve data from external systems, enabling Salesforce to act as a central hub for our business processes.
Whether you’re integrating with third-party services or connecting different Salesforce orgs, making callouts in Apex allows us to seamlessly extend Salesforce’s capabilities.
What are Callouts?
A callout in Salesforce basically refers to an HTTP request made by Salesforce to an external system. We do call out to external systems to fetch or send data. In other words, callouts allow Salesforce to communicate with systems outside of its own environment, which might include other Salesforce orgs, third-party APIs, or external databases.
Different types of Callouts
In Apex we have two types of callouts:
- SOAP Callouts: These callouts communicate with SOAP-based web services, which use XML as the data format.
- HTTP Callouts: In this type of callout data is typically exchanged in JSON format. We can use this to interact with Restful APIs.
Generally, HTTP callouts are often the preferred choice whenever possible because they are easier to understand and require less code. It is solely rely on JSON which is easy to read. It is widely used because of its simplicity.
However, SOAP is a little complex as compared to REST but still it is very much in use. It is particularly used in enterprise applications. Many traditional, enterprise-level applications still depend on SOAP for their web service integrations
In this blog, we will implement our scenario with REST Web Service.
What is a Remote Site Setting?
Before making any callout, we have to register the website first on the remote site or it will fail. It is a way of checking security in the Force.com platform so that only trusted websites can be accessed.
Let’s check how can we add our website in the remote site setting
To register our website, go to Setup –> Quick Find box –> Remote Site Setting –> New
Provide details like the Name of your Remote Site, URL and Disable Protocol Security means it will pass the information regardless of connection whether it is over HTTP or HTTPS. It means it can pass the data from HTTP to HTTP and vice versa. Click on Save and it will list down all the registered websites in your org.
What are Named Credentials?
Named credentials are the declarative way of storing our callback URL in Salesforce more securely. With Named Credentials it will be easy to manage the endpoint and all credentials stored under this will be encrypted. Below is the screenshot of how can we create the named credentials and what are other parameters required to save it.
So here we can specify the Name, URL which is basically the URL where we want to connect and also another authentication parameter. Storing our endpoint with named credentials makes it easy to maintain as it separates the callback URL and authentication from the callout definition. So suppose there are any changes required in the callback URL in future, we can just simply change it in our named credential itself and no need to change the Apex code. Hence all the callout referencing that named credentials will continue to work for it and it without any fail.
Named credentials support Apex callouts, External data sources, and External Services. With this we basically don’t need to put the physical URL in our code instead we can directly use the label of the named credential or can declare it via variable. Named credentials handle the process of storing the authentication token more safely in the org’s encrypted credential store, reducing the risk of exposure. Unlike remote site settings where authentication tokens are stored in a place in less secure.
Callout with Remote Site Setting
Below is the sample httpRequest code showing how can we use the remote site setting
xxxxxxxxxx
HttpRequest req = new HttpRequest();
req.setEndpoint('https://samplecallbackurl.com/api/resource');
req.setMethod('GET');
Callout with Named Credentials
Below is the sample httpRequest code showing how can we use named credentials
xxxxxxxxxx
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:Sample_NamedCredential/api/resource');
req.setMethod('GET');
What are External Credentials?
Before we create a Named Credential, we need to first create an External Credential. This specifies how to authenticate to an external system by defining the authentication method and which permission set or profile to use. The External Credential contains the details about how Salesforce will connect to the external system. We must create at least one External Credential before you can create a Named Credential that connects to it. Below is the screenshot showing how can we create the external credential.
Let’s understand how to make callouts in Apex with an Example
Here we will be integrating two different Salesforce org. For this, we will need two org where one will be the target org and another will be the source org. Here we will try to fetch the data from Source org and send it to Target org.
Following are things we need to create in our Target org
- Auth Provider
- Named Credentials
- Apex to fetch data from source org
Following are things we need to create in our Source org
- Connected App
- Apex which contains the web service for source org
We will be implementing this scenario by using Restful Service. Rest API is easy to use and lightweight. By Rest API we can do integration by using HTTP. It has the following methods available :
- POST – It used to insert new data
- GET – It used to retrieve any data
- PUT – It is used to update any data.
- DELETE – It is used to delete any data.
Target Org
Navigate to Auth Providers using the Quick Find box in Setup, then click New. This will display all available options. Since we are connecting with another Salesforce org, select Salesforce as the authentication provider.
Authentication providers (Auth Providers) enable third parties to access a Salesforce org using external providers like Apple, Google, and Facebook. In our case, it facilitates authentication between two Salesforce orgs, allowing users to log in to one org using their credentials from another.
After selecting our option as Salesforce it will again display a form to fill out details such as Name, consumer key, consumer secret, Endpoint URL etc.
The Consumer Key is a unique identifier provided by Salesforce when a connected app is created. It consists of a set of alphanumeric characters and, once generated, cannot be edited or overwritten. This key is essential for establishing a secure connection with Salesforce, ensuring that third-party applications are properly authenticated before accessing the system.
Additionally, it cannot be deployed from one org to another, and attempting to do so will result in an error.
The Consumer Secret is a private key generated alongside the Consumer Key. Both keys work together to securely authenticate and authorize access to an application.
Default Scopes define the permissions included in the request sent to an endpoint. Here, the name “MySFDCConnection” is used as an example.
For now, leave all fields as they are. After creating the connected app, we will return to enter values for the Consumer Key and Consumer Secret. Click Save—note that the callback URL will not be generated until these values are provided.
Source Org
Here, we can see two options Connected App and External Client App. Connected App is a way to connect our one Salesforce org to another Salesforce org. It is a framework that enables external providers to connect with Salesforce using API. Connected apps use these protocols to authenticate, authorize, and provide single sign-on (SSO) for external apps.
External Client App is the upgraded version or the new generation of the Connected App. They allow better security and are also package-able with 2GP (Second Generation Package) which is not available with Connected App.
In External Client Apps, admin and developer roles are distinct—developers handle settings, while admins manage policies. For now, we can proceed with the Connected App.
As shown above in the screenshot, check the Enable OAuth Settings. After checking it will add more fields for which we have to provide the value as shown below.
For now, enter a temporary URL in the callback URL field, select the required OAuth scopes, then leave the rest as is and click Save.
After clicking save, it will redirect it to the above page, click on continue. After that your connected app is ready. Now to generate the consumer key and secret, Click on Manage Consumer Details as shown below
Once you click, it will generate your consumer key and secret. Copy and save them, as we’ll need to add them to the Auth. Providers.
Now let’s move again to target org and open Auth Providers.
Target Org
Open Auth. Providers from Setup, Click on Edit for the one we have created and then paste the consumer key and secret that we generated from our source org.
As soon as we click on the Save button, it will give us the callback URL. Copy that callback URL and paste it in the Connected App where we have provided the temporary URL.
So now let’s create the External Credential first. To create, go to Setup and in the Quick Find box, search for Named Credential then External Credentials.
Provide a label, and choose OAuth 2.0 in the Authentication Protocol. In Identity Provider choose Auth Provider and then select the one which we have created.
Click on Save and now our External Credential is ready. After that let’s create a Named Credential as shown below.
Specify a label and enter the URL of the destination you want to connect to. In this case, it should be the URL of our source org.
Click on Save. Now Link the Named Credential with External Credential. Navigate to External Credential, Click new in Principal Section as shown below. Provide details like Parameter Name and choose Named Principal in Identity Type.
Additionally, set the scope to ‘full.’ Authentication will fail if the scope specified here doesn’t match the one used when creating the connected app.
Now we have to authenticate. To do so click on Authenticate as shown below.
As soon as we click on Authenticate it will redirect you to the login page. Provide the password and then Click on Allow Access on the pop, again you have to allow for External access.
Now we can see that the authentication status also changed from Not Configured to Configured. So now we have our orgs ready and we can create an Apex class. Let’s check how to make a callout in Apex.
To make a callout in Apex in this scenario we have to make a HTTP callout request from our target org to fetch data from our Source org.
Also in the target org give “External Credential Principal Access” access. Move your linked named principal to enable credential principal access to avoid authentication issues. We can also give this permission via permission set.
Target org
Source Org
How to make callout in Apex with Example of GET and POST
So now we have prepared our orgs so let’s implement the apex. Here we are creating the http request to get the records of the Case object and then we are inserting it in our Salesforce. Also, we will insert the record from target to Source.
Apex implementation in Target org for GET
xxxxxxxxxx
public class DemoHTTPCallout {
public static void makeCallout() {
try{
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:MySFDCNamedCred/services/apexrest/Case/');
req.setHeader('Content-Type', 'application/json');
req.setHeader('Accept', 'application/json');
req.setMethod('GET');
Http http = new Http();
HttpResponse response = http.send(req);
List<Case> caseList = new List<Case>();
System.debug('Response code: ' + response.getStatusCode());
System.debug('Response body: ' + response.getBody());
if (response.getStatusCode() == 200) {
String responseBody = response.getBody();
List<Object> caseRecievedList = (List<Object>) JSON.deserializeUntyped(responseBody);
System.debug('caseRecievedList: ' + caseRecievedList);
for (Object obj : caseRecievedList) {
if (obj instanceof Map<String, Object>) {
Map<String, Object> caseMap = (Map<String, Object>) obj;
Case ca = new Case();
ca.Subject = (String)caseMap.get('Subject');
ca.Status = (String)caseMap.get('Status');
caseList.add(ca);
}
}
System.debug('Case Received: ' + caseList);
System.debug('Case Received size : ' + caseList.size());
insert caseList;
} else {
System.debug('Error in HTTP Response. Status code: ' + response.getStatusCode());
System.debug('Response body: ' + response.getBody());
}
} catch (Exception e) {
System.debug('Exception caught with message : ' + e.getMessage());
System.debug('Line no: ' + e.getLineNumber());
}
}
}
Apex implementation in Source org for GET
xxxxxxxxxx
@RestResource(urlMapping='/Case/*')
global class SendDataToTarget {
@HttpGet
global static List<Case> getCases(){
System.debug('GET Method has been called');
return [Select Subject, Status from Case Limit 5];
}
}
Click on Execute and then as shown below we get the response code 200 which denotes success.
OUTPUT
As we can see we are getting the size as 5 with response code 200. Hence in the org, we can see the records get created because we have inserted the case List which we are getting from our Source org.
Let also understand how we can we create the record
Apex implementation in Target org for POST
xxxxxxxxxx
public class DemoHTTPCallout {
public static void makeCallout() {
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:MySFDCNamedCred/services/apexrest/Case/');
req.setHeader('content-type','application/json; charset=UTF-8');
req.setHeader('Accept', 'application/json');
req.setBody('{ "CaseOrigin": "Phone", "CaseStatus" : "New"}');
req.setMethod('POST');
Http http = new Http();
HttpResponse response = http.send(req);
System.debug('response code:'+response.getStatusCode());
System.debug('response body : '+response.getBody());
}
}
Apex implementation in Source org for POST
xxxxxxxxxx
@RestResource(urlMapping='/Case/*')
global class SendDataToTarget {
@HttpPost
global static Case createCase(String CaseStatus, String CaseOrigin){
Case ca = new Case();
ca.Status = CaseStatus;
ca.Origin = CaseOrigin;
System.debug('Post Method has been called');
insert ca;
return ca;
}
}
OUTPUT
Above we are creating a Case record by hitting api from target to Source. We have provided the JSON body where we have given the field value. It will create the Case record in the Source record. In the Source org, we can see that we get the debug with success.
Also Read – Apex Trigger Best Practices in Salesforce
FAQ’s
1. What are the ways we used to do callout in async apex?
Below are the different annotations we can use to do callouts in respective async class
- Queueable: Database.AllowsCallouts ( We need to implement it with after queueable interface)
- Batchable: We need to implement a Database.AllowsCallouts.
- Future: To do a callout we have to use one extra parameter @future(callout=true).
- Schedular: Callout from Schedular is not supported. Instead, we can use other async and then call that in the Scheduler class.
2. What possible error can we get if we don’t provide the same scope as mentioned in the connected app?
So if we don’t provide the same access mentioned in the connected app, while authenticating the org we might get the below “OAUTH_APPROVAL_ERROR_GENERIC : An unexpected error has occurred during authentication. Please try again”.
3. What are the best practices for making callouts?
Following are the few best practices we can consider :
- Always consider governor limits while performing callouts.
- Always handle the exception.
- Optimise your API Call limit.
- Make a callout using the Batch class to get a new set of limits with each execution.
4. What are the governor limits we can consider?
Following are the few governor limits we can consider :
- A transaction can make a maximum of 100 callouts to an HTTP request or an API call.
- In Developer Edition orgs, we can only make up to 20 concurrent callouts to endpoints outside of your Salesforce org’s domain.
- We make the callout if there is already some pending operation in the same transaction.
Conclusion
In conclusion, making callouts in Apex is an essential skill for Salesforce developers. It is a powerful feature that allows Salesforce to communicate with external systems. By using HTTP methods such as GET, POST, PUT, and DELETE, we can send and receive data from external APIs. As demonstrated in the example, the important step is to make our org ready first by creating external credentials, named credentials, and auth providers and to authenticate the org where we want to connect and create a connected app. Then we can move forward to write our Apex code to make callouts.