Update Custom Metadata Record in an External Salesforce Org Using SOAP API

Update Custom Metadata Record in an External Salesforce Org Using SOAP API

Org to Org Integration Demystified

Background:

Recently, I worked on a project where I needed to update a custom metadata record in an external Salesforce org. Our source org held a list of configurations, each corresponding to an external org. Whenever a configuration was updated in the source org, it had to be reflected in the custom metadata record of the respective external org.

Use Case for this blog post:

In this post, we'll write Apex code to update a field value in a custom metadata-type record.

The Custom Metadata Type details:

  • Label - Presentify Integration Settings

  • API Name - Presentify_Integration_Setting__mdt

  • Record Name - Template_Presentation_ID

  • Field API Name - Value__c

Code

Below is a rough draft of the code. Feel free to refactor it according to your requirements & make it better.

💡
Unlike the more common REST API, which uses JSON... SOAP API works with XML data. Here, we'll prepare XML for our request.
public class customMetadataUtility {

    // Method to retrieve the Access Token for an external Salesforce org
    public static String getAccessTokenOfExternalOrg(String instanceUrl) {
        // Step 1 - Implement your own logic to get the Access Token for the external org
        // Example: Use a named credential or an authentication flow
        // Step 2 - Return the Access Token
        return 'YOUR_ACCESS_TOKEN';
    }

    public static HttpResponse updateCustomMetadata(String instanceUrl, String templatePresentationId) {

        // Retrieve the access token
        String accessToken = getAccessTokenOfExternalOrg(instanceUrl);

        // Construct the API endpoint URL for SOAP API
        String apiEndpoint = instanceUrl + '/services/Soap/m/61.0';

        // Construct the SOAP request body
        String body = '<?xml version="1.0" encoding="UTF-8"?>'
            + '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
            + '<soapenv:Header xmlns="http://soap.sforce.com/2006/04/metadata">'
            + '<SessionHeader>'
            + '<sessionId>'+accessToken+'</sessionId>'
            + '</SessionHeader>'
            + '</soapenv:Header>'
            + '<soapenv:Body xmlns="http://soap.sforce.com/2006/04/metadata">'
            + '<updateMetadata>'
            + '<metadata xsi:type="CustomMetadata">'
            + '<fullName>Presentify_Integration_Setting__mdt.Template_Presentation_ID</fullName>'
            + '<label>Template Presentation ID</label>'
            + '<protected>false</protected>'
            + '<values>'
            + '<field>Value__c</field>'
            + '<value>'+templatePresentationId+'</value>'
            + '</values>'
            + '</metadata>'
            + '</updateMetadata>'
            + '</soapenv:Body>'
            + '</soapenv:Envelope>';

        // Set up the HTTP request
        HttpRequest req = new HttpRequest();
        req.setEndpoint(apiEndpoint);
        req.setMethod('POST');
        req.setHeader('Authorization', 'Bearer ' + accessToken);
        req.setHeader('Content-Type', 'text/xml');
        req.setHeader('SOAPAction', '""');
        req.setBody(body);

        // Send the HTTP request and get the response
        Http http = new Http();
        HttpResponse response = http.send(req);

        // Check the response status and return info or throw an error
        if (response.getStatusCode() == 200) {
            return response;
        }else{
            throw new CalloutException('Failed to update metadata: ' + response.getBody());
        }
    }

}

Gotchas

  1. Access Token Logic: The code doesn’t include logic to generate the access token. You can implement this using named credentials, authentication flows, or connected apps to get the access token. The instanceUrl is passed into the getAccessTokenOfExternalOrg method to identify which org to get the access token for (it is optional though)

  2. Name of the Custom Metadata Record in the request body

    1. This is stored in the <fullName> tag

    2. It has two parts to it, the API Name of your Custom Metadata & the Name of your Custom Metadata Record, joined by a .

    3. Example - Custom_Metadata__mdt.Record_Name

  3. Updating Multiple Fields: The above example updates one field (Value__c). To update multiple fields, include additional <values> tags:

    1.   <values>
            <field>FIELD_1_API_NAME__c</field>
            <value>FIELD_1_Value</value>
        </values>
        <values>
            <field>FIELD_2_API_NAME__c</field>
            <value>FIELD_2_Value</value>
        </values>
      

Call the code

customMetadataUtility.updateCustomMetadata('<INSTANCE_URL_OF_THE_EXTERNAL_ORG>', '<VALUE_TO_BE_UPDATED>');