In this tutorial, we’ll briefly go through the process of merging all Salesforce SFDC documents using PDF.co.

Let’s go through the quick steps.

  1. Create Site Settings in the Salesforce Org
  2. Create an Apex Class in Salesforce
  3. Source Code
  4. Specify PDF.co API Key
  5. Upload Files into Salesforce System
  6. Verify the Source Code
  7. Check the Output
  8. Useful Resources
  9. Demo Video

1. Create Site Settings in the Salesforce Org

Create three remote site settings in the Salesforce Org as shown in the following screenshots. Here, the API URL is “https://api.pdf.co”.

Create Site Settings in the Salesforce Org

Create Remote Site Settings in the Salesforce Org

Remote Site Settings Salesforce Org

2. Create an Apex Class in Salesforce

The next step is to create an Apex class in Salesforce as shown in the following screenshot and add source code there.
In order to do that, first, we need to open the “Developer Console”.

Create an Apex Class in Salesforce

Now, let’s create an Apex class. For that, click on “Files” > “New” > “Apex Class”.

Apex Class in Salesforce

Have the class name like “MergeDocumentsFromUploadedFiles” and click “Ok”. Once a file is created, just put all source code there.

3. Source Code

Here’s the source code for that.

public class MergeDocumentsFromUploadedFiles {
    
    String API_KEY = '***************';  
    String[] fileName = new String[] {'images-and-documents', 'Input', 'sample1'}; // File name which is available in salesforce Files.
    string destinationFile =  'MergeResultByUpload'; //This is the Desitantion File Name.
   
    List urlList = new List();
    public void startProcessing()
    {
        try
        {
            for(String fname : fileName)
            {
                ContentVersion cv = [select Title, VersionData from ContentVersion where Title = :fname limit 1];
                Blob SourceFile  = cv.VersionData;
                //1. Prepare URL for "Get Presigned URL" API call
                string url = 'https://api.pdf.co/v1/file/upload/get-presigned-url?contenttype=application/octet-stream&name=:fname'; 
                HttpRequest req = new HttpRequest();
                req.setHeader('x-api-key', API_KEY);
                req.setEndpoint(url);
                req.setMethod('GET');
                req.setTimeout(60000);
                Http http = new Http();
                HTTPResponse res = http.send(req);
                if(res.getStatusCode() == 200) 
                {
                    System.Debug('res ' + res);
                    Map<String, Object> deserializedBody =  (Map<String, Object>)JSON.deserializeUntyped(res.getBody());
                    Boolean isError = Boolean.ValueOf(deserializedBody.get('error'));
                    if(isError == false)
                    {
                        // Get URL to use for the file upload
                        String uploadUrl = String.ValueOf(deserializedBody.get('presignedUrl'));
                        // Get URL of uploaded file to use with later API calls
                        String uploadedFileUrl = String.ValueOf(deserializedBody.get('url'));
                        SYstem.debug('uploadedFileUrl :: '+uploadedFileUrl);
                        // 2. UPLOAD THE FILE TO CLOUD.
                        if(uploadFile(API_KEY, uploadUrl, SourceFile))
                        {
                            // Merge Documents and download
                            urlList.add(uploadedFileUrl);  
                            System.debug('urlList ' + urlList);
                            //System.assert(false, ' urlList ' + urlList);
                        }
                    }
                }
                else
                {
                    System.debug('Error Response ' + res.getBody());
                    System.Debug(' Status ' + res.getStatus());
                    System.Debug(' Status Code' + res.getStatusCode());
                    System.Debug(' Response String' + res.toString());
                } 
            }
            if (urlList.size() > 0)
            {                
                // 2. MERGE UPLOADED PDF DOCUMENTS
                MergeDocToPDF(urlList);
            }
        }
        catch(Exception ex)
        {
            String errorBody = 'Message: ' + ex.getMessage() + ' -- Cause: ' + ex.getCause() + ' -- Stacktrace: ' + ex.getStackTraceString();
            System.Debug(errorBody);
        }
        
    }   
    
    @TestVisible
    public static boolean uploadFile(String API_KEY, String url, Blob sourceFile)
    {
        HttpRequest req = new HttpRequest();
        req.setHeader('x-api-key', API_KEY);
        req.setHeader('Content-Type', 'application/octet-stream');
        req.setEndpoint(url);
        req.setMethod('PUT');
        req.setTimeout(60000);
        req.setBodyAsBlob(sourceFile);
        Http http = new Http();
        HTTPResponse res = http.send(req);
        if(res.getStatusCode() == 200) 
        {
            System.Debug(res.getBody());
            return true;
        }
        else
        {
            System.debug('Error Response ' + res.getBody());
            System.Debug(' Status ' + res.getStatus());
            System.Debug(' Status Code' + res.getStatusCode());
            System.Debug(' Response String' + res.toString());
            return false;
        }
    }
    
    public void MergeDocToPDF(List uploadedFileUrl)
    {
        try
        {
            string filesUrl = string.join(uploadedFileUrl,',');            
            Map<string, Object> parameters = new Map<string, Object>();
            parameters.put('url', filesUrl);
            string jsonPayload = Json.serialize(parameters);
            
            string url = 'https://api.pdf.co/v1/pdf/merge2';
            HttpRequest req1 = new HttpRequest();
            req1.setBody(jsonPayload);
            req1.setHeader('x-api-key', API_KEY);
            req1.setHeader('Content-Type', 'application/json');
            req1.setEndpoint(url);
            req1.setMethod('POST');
            req1.setTimeout(60000);
            Http http = new Http();
            HTTPResponse res1 = http.send(req1);
            if(res1.getStatusCode() == 200) 
            {
                Map<String, Object> deserializedBody =  (Map<String, Object>)JSON.deserializeUntyped(res1.getBody());
                Boolean isError = Boolean.ValueOf(deserializedBody.get('error'));
                if(isError == false)
                {
                    SYstem.debug('res1.getBody() :: '+res1.getBody());
                    String urlVal = (String)deserializedBody.get('url');
                    downloadPDFAndStore(urlVal, destinationFile);
                }
            }
            else
            {
                System.debug('Success Response ' + res1.getBody());
                System.Debug(' Status ' + res1.getStatus());
                System.Debug(' Status Code' + res1.getStatusCode());
                System.Debug(' Status String' + res1.toString());
            }
        }
        catch(Exception ex)
        {
            String errorBody = 'Message: ' + ex.getMessage() + ' -- Cause: ' + ex.getCause() + ' -- Stacktrace: ' + ex.getStackTraceString();
            System.Debug(errorBody);
        }
    }
    
    @TestVisible
    private static void downloadPDFAndStore(String extFileUrl, String DestinationFile)
    {
        Http h = new Http(); 
        HttpRequest req = new HttpRequest(); 
        extFileUrl = extFileUrl.replace(' ', '%20'); 
        req.setEndpoint(extFileUrl); 
        req.setMethod('GET'); 
        req.setHeader('Content-Type', 'application/pdf');
        req.setCompressed(true); 
        req.setTimeout(60000); 
        //Now Send HTTP Request
        HttpResponse res  = h.send(req); 
        if(res.getStatusCode() == 200) 
        {
            blob fileContent = res.getBodyAsBlob();
            ContentVersion conVer = new ContentVersion();
            conVer.ContentLocation = 'S'; // to use S specify this document is in Salesforce, to use E for external files
            conVer.PathOnClient = 'result' + '.pdf'; // The files name, extension is very important here which will help the file in preview.
            conVer.Title = DestinationFile; // Display name of the files
            conVer.VersionData = fileContent;
            insert conVer;
            System.Debug('Success');
        }
        else
        {
            System.debug('Error Response ' + res.getBody());
            System.Debug(' Status ' + res.getStatus());
            System.Debug(' Status Code' + res.getStatusCode());
            System.Debug(' Response String' + res.toString());
        }
    }
}

4. Specify PDF.co API Key

In the “MergeDocumentsFromUploadedFiles” Apex class file, please replace the value of variable “API_KEY” with PDF.co API Key. Also, add the destination file name which will be stored as a PDF.

Specify PDF.co API Key

PDF.co API key is necessary for authentication of PDF.co requests. One can obtain PDF.co API Key by signing up at PDF.co.

5. Upload Files into Salesforce System

We also need to upload various format files such as ‘XLS’, ‘PDF’, ‘ZIP’ in the Salesforce File System. These files will be used in this merge demo.

To upload files to SFDC records, go to “App Launcher” and click on “Files”. It’ll open a file upload popup where we need to select and upload files.

Upload Files into Salesforce System

6. Verify the Source Code

Now, to verify the source code, please open the “Execution Anonymous Window”.

Verify the Source Code

Once the window is opened, write the following code to invoke merge processing.

Enter Apex Code

Finally, click on the “Execute” button to start processing.

7. Check the Output

Once execution is complete, we can check the output by going to “App Launcher” again. There we should find the output file.

Check the Output

Useful Resources

Following are some useful resources.

Please try this sample in your machine for a better understanding. Thank you!

Demo Video