Salesforce Metadata API

Lubomyr Voloschak
5 min readApr 18, 2021

--

Hello world, this is the first time that I decided to write a short note on the internet. This note will be about how to use Salesforce Metadata API. I am sure there is plenty of similar information and there are already some tools that do the same things with communication via Metadata API. The official documentation has been well written, but I did not find any good examples of how to use it and the information that I found was not enough for me. I decided to create a package.xml generator and in that way learn more about the API.

First of all, we need to obtain a few things from your Salesforce application: Organization ID, Salesforce Org base URL and Session ID. With this information, the Metadata API manual and a little patience we can do a lot of interesting things. I will be using a cULR as an example, but you can use other tools for transferring data using network protocols.

So, how to get the authorization information? Execute the following Apex code in your Salesforce application. You can execute anonymous Apex in VS Code or in Developer console:

System.debug('OrgId: '+ UserInfo.getOrganizationId());
System.debug('BaseUrl: '+ Url.getOrgDomainUrl() + '/');
System.debug('SessionId: '+ (UserInfo.getSessionId()).substring(1));
  1. How to get a list of all metadata from your Salesforce application? Create a file, with the following content:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header>
<n1:SessionHeader xmlns:n1="http://soap.sforce.com/2006/04/metadata">
<n1:sessionId>sessionIdVar</n1:sessionId>
</n1:SessionHeader>
</env:Header>
<env:Body>
<n1:describeMetadata xmlns:n1="http://soap.sforce.com/2006/04/metadata">
<n1:type type="xsd:string">50.0</n1:type>
</n1:describeMetadata>
</env:Body>
</env:Envelope>

You should replace the sessionIdVar with your SessionId before proceeding. As an example, I called my file describeMetadata.xml this allows me to execute a command with HTTP request in the command line:

curl BaseUrl/services/Soap/m/50.0/OrgId -d @describeMetadata.xml -H 'Content-Type: text/xml' -H "SOAPAction: ''" -v

Where BaseUrl and OrgId are your values from Apex code and the is the name of the file describeMetadata.xml that you have created. This command above will get you all the metadata from your Salesforce application.

You will get an XML file as a response and that file will contain section called <result> with an array of <metadataObjects>, each element has <xmlName>componentType</xmlName> property. The variable called componentType can be anything: CustomTab, ApexClass, PermissionSet etc.

2. How to get a list of all components with specific component types? To do this create a second file, with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<env:Header>
<n1:SessionHeader xmlns:n1="http://soap.sforce.com/2006/04/metadata">
<n1:sessionId>sessionIdVar</n1:sessionId>
</n1:SessionHeader>
</env:Header>
<env:Body>
<n1:retrieve xmlns:n1="http://soap.sforce.com/2006/04/metadata">
<n1:retrieveRequest type="tns:RetrieveRequest">
<n1:apiVersion type="xsd:double">50.0</n1:apiVersion>
<n1:singlePackage type="xsd:boolean">TRUE</n1:singlePackage>
<n1:unpackaged type="tns:Package">
<types>
<members>*</members>
<name>componentType</name>
</types>
<version>50.0</version>
</n1:unpackaged>
</n1:retrieveRequest>
</n1:retrieve>
</env:Body>
</env:Envelope>

As with the previous example you should replace the sessionIdVar and componentType with your values.

The component type — can be any valid value that you received from the previous response. For example, if request ApexClass then you will get all Apex Classes from your application.

In my case, it is called retrieveRequest.xml. Then just run this command from the command line:

curl BaseUrl/services/Soap/m/50.0/OrgId -d @retrieveRequest.xml -H 'Content-Type: text/xml' -H "SOAPAction: ''" -v

You will get a response with some similar XML file:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://soap.sforce.com/2006/04/metadata">
<soapenv:Body>
<retrieveResponse>
<result>
<done>false</done>
<id>09S09000004MZpsEAG</id>
<state>Queued</state>
</result>
</retrieveResponse>
</soapenv:Body>
</soapenv:Envelope>

The ID value will be different for each of your requests. Now we have the request-id, but to get the data that we requested the <state> property should change the value from Queued to In Progress and after that to Done, usually, you can try to get the data immediately but sometimes it takes a while.

3. How to get the result with the requested data and ID? Create a third file, with the following content:

<?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>sessionIdVar</sessionId>
</SessionHeader>
</soapenv:Header>
<soapenv:Body xmlns="http://soap.sforce.com/2006/04/metadata">
<checkRetrieveStatus>
<id>queuedIdVar</id>
<includeZip>false</includeZip>
</checkRetrieveStatus>
</soapenv:Body>
</soapenv:Envelope>

Change the queuedIdVar with an id that you got from the previous response, as an example for me it was 09S09000004MZpsEAG and sessionIdVar as usual with your value. Then run the next command from the command line:

curl BaseUrl/services/Soap/m/50.0/OrgId -d @retrieveResponse.xml -H 'Content-Type: text/xml' -H "SOAPAction: ''" -v

I called my third file the retrieveResponse.xml, you will receive a response that is an XML file and each of the properties block will contain a component that describes the selected type.

4. How to get Object details? Create a new file, suppose it is called objectRequest.xml, with the following content:

<?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>sessionIdVar</sessionId>
</SessionHeader>
</soapenv:Header>
<soapenv:Body xmlns="http://soap.sforce.com/2006/04/metadata">
<readMetadata>
<type>CustomObject</type>
<fullNames>objectNameVar</fullNames>
</readMetadata>
</soapenv:Body>
</soapenv:Envelope>

Where the objectNameVar is your selected object name for example Account and your sessionIdVar value, then repeat a request:

curl BaseUrl/services/Soap/m/50.0/OrgId -d @objectRequest.xml -H 'Content-Type: text/xml' -H "SOAPAction: ''" -v

Please, take a look at the following <soapenv:Body> block:

<soapenv:Body xmlns="http://soap.sforce.com/2006/04/metadata">
<methodName>
<param>value</param>
<param>value</param>
</methodName>
</soapenv:Body>

You probably noticed that for each of the new files that we created, we changed the name of the method and parameters.

Here the <methodName> section can be any valid values from API documentation, from the last example it was the <readMetadata>. It can be any valid value like <createMetadata>, <listMetadata> etc.

And the <param>value</param> values are <type>CustomObject</type> and <fullNames>objectNameVar</fullNames>.

Also, do not forget to update the Salesforce API version from 50.0 to a new one if you read this in a later Salesforce release.

The main Metadata API calls are:

The Metadata API contains a lot of methods and I can not describe everything in this short note, you can try by yourself how it works.

While learning all these things I created a package.xml generator, and to see how it looks you can read source code. This is something I have used myself in my work to retrieve a list of metadata components and do the deployment process at that time. It saved me a lot of effort and time, and I learned something new.

Here is a link to the application.

Continue learning new tech and thanks for your time.

Regards, Lubomyr

--

--