Part One: SOAP-based APIs Simple Object Access Protocol (SOAP) is a messaging protocol based on requests and responses using an XML format. Although some legacy systems still use SOAP over SMTP, the transport method typically used for SOAP requests is HTTP. As an API protocol, SOAP is platform- and language-agnostic, allowing for two applications running on completely different systems to communicate with one another. This post is part of a two-part series covering how to create custom API endpoints in Salesforce with APEX. In Part One, we’ll walk through how to create a SOAP-based API endpoint for other applications to use when communicating with your Salesforce org. A Brief Introduction to SOAP Each SOAP message is contained in an “envelope,” which has a header and a body. The header contains application-related information, such as the date when the message was generated or ids related to the message context. The body contains the actual message. Here is an example SOAP message with a format that would be used for authenticating to Salesforce: <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:enterprise.soap.sforce.com"> <soapenv:Header> <urn:LoginScopeHeader> <urn:organizationId>12345</urn:organizationId> <urn:portalId>abcde</urn:portalId> </urn:LoginScopeHeader> </soapenv:Header> <soapenv:Body> <urn:login> <urn:username>johndoe</urn:username> <urn:password>mypassword</urn:password> </urn:login> </soapenv:Body> </soapenv:Envelope> Since each message has the same structure, SOAP is system agnostic. For example, an application running on a Windows 11 machine can send a message to another application running on a Unix-based web server. Though the message can be sent using SMTP or HTTP, SOAP messages should ideally be sent with HTTPS, with either simple or mutual authentication. SOAP is mostly used to create an or to exchange server-to-server information. Therefore, it is very important for the two systems to establish trust. Salesforce provides multiple ways to accomplish authentication. API web service The relationship between SOAP and WSDL Although all SOAP messages have the same structure, the SOAP specification doesn’t define other aspects, such as message format or transport protocol. The Web Services Description Language (WSDL) describes the message formats, transport details, and operations of the web service. The WSDL file can be considered a contract between the client and the service. How to Create a SOAP-based API in Salesforce Now that we have covered the fundamentals let’s begin implementing our SOAP API. Set up a Salesforce org First, you need a Salesforce org. Salesforce provides free Developer edition orgs, and signing up for one is straightforward. Go to the and provide your details. You should receive an invite link within a few minutes. sign-up page Creating a global class with Apex To create a SOAP web service in Salesforce, we will need to create a globally defined Apex custom class. In our class, we’ll use the keyword and definition modifier for every method we want to expose. Adding the keyword automatically gives global access to the method it is added to. webservice static webservice In order to create this class in our shiny, new org, we go to , and then find . In the table listing existing classes, we click . Setup Custom Code -> Apex Classes New To learn more about Apex and how to create classes, check out this and the . Trailhead page Apex documentation Below, we have a sample class that exposes a method used to create new Contact records in Salesforce. The method accepts a Contact’s details as parameters and inserts a new Contact record. ContactAPI createContact If successful, it returns the ID of the newly created Contact along with a message. In case of a failure, it returns an error message. Please copy the code and paste it into the newly created empty class. global class ContactAPI { webservice static String createContact (String firstName, String lastName, String contactEmail, String salutation) { try { Contact newContact = new Contact(); newContact.Salutation = salutation; newContact.FirstName = firstName; newContact.LastName = lastName; newContact.Email = contactEmail; insert newContact; return 'Successfully inserted new Contact! Id:' + String.valueOf(newContact.Id); } catch (Exception e) { return 'Error:' + e.getMessage(); } } } Next, we click . Save That’s it! Our web service is ready for operations. We have successfully created a SOAP API in Salesforce. Generate the WSDL We now need to generate a WSDL file and provide it to the external application or third-party developers who can then consume it to call our method. createContact Salesforce provides two out-of-the-box WSDL files to integrate client applications with Salesforce: The is optimized for a single Salesforce org. It’s strongly typed, meaning it contains objects and field definitions for this particular org. Whenever there is a change in the metadata (object and/or fields) in the Salesforce org, a new WSDL needs to be generated and provided to the client (to consume again). Enterprise WSDL The is optimized for use with many Salesforce orgs. It’s loosely typed, and it doesn’t change based on an org’s specific configuration. Partner WSDL In order to utilize our web service, we’ll use the WSDL for our Apex class (to actually call our web service), and we’ll use the Enterprise WSDL to authenticate to Salesforce. After creating our class, we see it show up in the list of Apex classes. In the row for ContactAPI, we click on the link to generate a WSDL. ContactAPI WSDL This will open a new tab with our WSDL, which will look similar to this: We save this file to our local machine, naming it . contactAPI-wsdl.xml To generate the Enterprise WSDL for our Salesforce org, we go to the Setup page, and then find . Then, we click on . Integrations -> API Generate Enterprise WSDL Your generated WSDL should look similar to this: We save this file to our local machine, naming it . enterprise_wsdl.xml To generate the WSDL for your Apex Class: Go to the Setup page. Type and select Apex Classes. Find your class. In our case, it’s ContactAPI. Click on the name. On the next screen, you will have the class page where you have the button. Generate WSDL Test and validate To ensure that the web service works, we’ll consume it by calling it from our web application and see if it responds correctly. We’ll also cover how to validate our API with unit testing. Consume the API For the purpose of this demo, we’ll use , which is an open-source tool to test SOAP (and other protocols) web services. With SoapUI installed and running, we create a new SOAP Project, providing a name and selecting our file as the initial WSDL. SoapUI enterprise_wsdl.xml We now have all available Salesforce SoapBindings listed on the left. First, we need to authenticate our web application to Salesforce. We do this by using the call and providing our login credentials. login Use a security token For added security, we also need to add a to our password to authenticate. We can get a security token by going to the page and selecting on the left. Then, press the button with the same name. We will then receive our security token by email. Security Token Settings Reset My Security Token Log in with the token and credentials With our token in hand, we select the SoapBinding in SoapUI. Ensure you have the correct URL depending on your org. If you just signed up for a developer account, the URL should be . If you are testing this in a Sandbox, then the URL should be . Ideally, the generated Enterprise WSDL will already have the correct URL. login https://login.salesforce.com https://test.salesforce.com For demo testing, we can comment out all other parameters except username and password. We press the green button on the top left of the window to send the request. We receive a response that looks like this: Play The critical pieces that we are looking for in the response are and . In order to call our web service, we need to provide the together with other parameters in our call. We copy down this , as we will need this later. sessionId serverUrl sessionId sessionId Call our SOAP API Let’s call our class and create a Contact in Salesforce. To do this, we need to add our ContactAPI WSDL file, , to our project. We right-click on the project folder and select . ContactAPI contactAPI-wsdl.xml Add WSDL After adding the WSDL, it also appears in the left menu like below. Double-click on to see the request. For this example, we can remove everything from the SOAP envelope header except for the with node. Request 1 SessionHeader sessionId After removing the unwanted nodes, we provide the that we copied from our login call earlier. Then, in the section of the envelope, we provide the details of the contact to be created. sessionId Body We press the green button on the top left. Vóila! We have successfully created a Contact in Salesforce and received its . Play Id Check Salesforce org for new contact Let’s look inside our Salesforce org to see if everything was created correctly. We go to our Salesforce org, click the waffle icon on the left and then type in the search bar to find and select . App Launcher Contact Contacts By default, we land on the Contacts page with the list view. Click the down arrow and select either or list view. Recently Viewed Contacts All Contacts My Contacts : If you are in a Developer org, you will see a bunch of dummy Contacts (and other records) that Salesforce creates for you to test the platform. Note We type the name of our newly created contact in the list search box on the right, and we see our new contact! When we click on the Contact name, we end up on the Details page for that Contact. Call our SOAP API with invalid data Lastly, in order to ensure that our API is working properly, let’s send a bad request to see what we get as a response. We’ll simply send another request to our SOAP web service, but this time replace the in the email address with a instead. . , This time, we receive an (as we programmed in the API). error message The entire error message reads like this: Error:Insert failed. First exception on row 0; first error: INVALID_EMAIL_ADDRESS, Email: invalid email address: sheila@gmail,com: [Email] This shows that our SOAP-based API is working as designed. With this foundation, we can build other SOAP-based APIs to create records for different objects. Unit Testing Besides consuming our SOAP-based API, another way to validate it works properly is through testing. Test Driven Development (TDD) is at the core of Salesforce development. To ensure the stability and reliability of the platform, Salesforce requires your custom code to have a minimum of 75% code coverage via unit tests in order to deploy it to a production environment. Let’s create some unit tests for our web service. @isTest private class TestContactWebService { static testMethod void testInsertNewContact() { // Create test data for positive test String salutation = 'Mr.'; String firstName = 'Max'; String lastName = 'Bond'; String emailAddress = 'm.bond@mi5.gov.uk'; Test.startTest(); //Call the method with parameters String result = ContactAPI.createContact(firstName, lastName, emailAddress, salutation); Test.stopTest(); Contact newContact = [SELECT FirstName FROM Contact WHERE LastName = 'Bond']; System.assertEquals(newContact.FirstName, 'Max', 'Assert Error: Please check the ContactAPI class'); } static testMethod void testInsertNewContactFail() { // Create test data for failing test String salutation = 'Mr.'; String firstName = 'Max'; String lastName = 'Bond'; // The email address has , instead of . String badEmailAddress = 'm.bond@mi5,gov,uk'; Test.startTest(); //Call the method with parameters String result = ContactAPI.createContact(firstName, lastName, badEmailAddress, salutation); Test.stopTest(); // This should contain the Error substring that we added to the catch block above. System.assert(result.contains('Error:'), 'Fail Assert Error: Please check the ContactAPI class'); } } In our unit test, we created two scenarios: a “happy path” that verifies valid inputs result in a newly created Contact record, and a “sad path” where we expect the API to return an error on invalid inputs. Salesforce also provides a . Trailhead on unit testing in Apex Conclusion In this post, we only scratched the surface in terms of the capabilities that Salesforce provides when it comes to SOAP. As we saw, the generated Enterprise WSDL makes a long list of SoapBindings available. In addition, we can create our own custom classes and SOAP-based web services. If you have a (legacy) application that uses SOAP to communicate with other systems, you now have the tools to connect that application to your Salesforce org. With enterprise-level security baked into the platform, you can be sure that your connection is safe and your data is protected. In Part Two of our series, we’ll cover REST APIs, demonstrating how to use Apex to create a custom REST API endpoint for our Salesforce org.