Conga Product Documentation

Welcome to the new doc site. Some of your old bookmarks will no longer work. Please use the search bar to find your desired topic.

Creating the Merge Call using Apex Call

This topic describes the details and sample code to send your Merge request to Conga Platform, using the bearer token you already obtained in the getAuth() method found in Authentication using Apex Call.

Now that you have a bearer token saved in theauthTokenvariable, the next step is to create and send the Mergerequest to Conga. Here are the goals for this method:

  • Method Declaration
  • Creating an HTTP request
  • Set our Endpoint, Request Method, Headers, and Body for the API call
  • Create an Http container to hold our response
  • Creating our Http Instance
  • Sending our Http request
  • Checking the Response Status
  • Logging the Response
  • (Optional) Parsing the Response

Step-by-step Breakdown of startMerge()

Method Declaration - public static void startMerge()

The method startMerge() is declared as private and static, just like the getAuth() method. Private means it can only be called from within the same class. Static means it belongs to the class itself rather than an instance of the class. This method is responsible for taking the existing authToken and using it to initiate the actual merge process against Conga Merge endpoint.

Creating an HTTP Request - HttpRequest mergeRequest = new HttpRequest();

A new instance of HTTP Request in created. This object is used to configure and send our HTTP request to the Merge API endpoint. Similar to the auth call, this is the container for all request details.

Setting Endpoint URL - mergeRequest.setEndpoint(mergeURL);

The endpoint for the HTTP request is set to the mergeURL. This should already be defined at the top of your class: private static final String mergeUrl = 'https://coreapps-rlspreview.congacloud.com/api/ingress/v1/Merge'; This URL tells the request where to send the merge instructions within Conga Platform.

Specifying the HTTP Method - mergeRequest.setMethod('POST');

The HTTP method is set to POST. This method uses POST here because you are sending data (the merge configuration and merge fields) to the server, which will then process that data and generate a merged document.

Setting Request Headers -

You're going to set three important headers:
  • mergeRequest.setHeader('Authorization', 'Bearer ' + authToken);
  • mergeRequest.setHeader('Content-Type','application/json');

  • mergeRequest.setHeader('Accept','application/json');

Here is what each of these is doing:
  • Authorization:

    • This header includes the bearer token that was retrieved in getAuth().

    • The format is Bearer <tokenValue>.

    • Without this header, the Conga API will not recognize or authorize the request.

  • Content-Type:

    • Set this to application/json to indicate that the body of the request is JSON

    • The Conga Merge endpoint expects a JSON payload describing templates, destinations and merge data.

  • Accept:

    • This header indicates what type of response is expected to handle.

    • Setting application/json tells the API a JSON response is expected back.

Building the Request Body - Overview

The request body for the merge call is a JSON object made up of several key pieces:

  • LegacyOptions– optional legacy configuration (like output file name).
  • templateSources– the template(s) to merge against.
  • destinations– where to store the merged output.
  • jsondata– the actual merge field data in JSON format.

You will construct each of these as Apex collections (Map and List), then serialize them into a single JSON object that can be sent in the body.

Adding Legacy Options - mergeData.put('LegacyOptions', new Map<String, String>{'OFN' => 'mergingFromCongaDrive'});

These are some Legacy Options that can be mapped to our top-level mergeData map.

  • OFN stands for Output File Name.
  • In this example, the output file name will be set to"mergingFromCongaDrive".
  • This value can be changed to anything you'd like your merged document to be named.
This field can also be extended with additional legacy options if required by your specific use case.

Defining templateSources -
mergeData.put('templateSources', new List<Map<String, String>>{
    new Map<String, String>{
        'integrationName' => 'conga',
        'fileId'          => fileId
    }
});
This section tells Conga which template to user for the merge:
  • integrationName - Typically set to 'conga' when using Conga Drive as the integration.

  • fileID - this is the ID of the template stored in Conga Drive. This was defined earlier as: private string final String fileId= 'bd533afe-173b-4347-90eb-56f9f2b55db4'; This is wrapped in a List<Map<String, String>> because the API supports multiple templates. In this example it is only one.

Defining Destinations -
mergeData.put('destinations', new List<Map<String, String>>{
    new Map<String, String>{
        'integrationName' => 'conga',
        'folderId'        => 'root'
    }
});
This section describes where the merged output should be stored.
  • integrationName - Set to 'conga', indicating Conga Drive as the integration destination.

  • folderId - 'root' indicates the final merged document will be stored in the root folder. If using a specific folder id, replace 'root' with the appropriate folder ID. Just like templateSources, ths can be multiple values to indicate multiple destinations.

Preparing the Merge Field Data (jsonData) -

Now define the actual data that will populate your merge fields in the template.
mergeData.put('jsondata', JSON.serialize(new Map<String, String>{
    'firstname' => 'SampleData',
    'lastname'  => 'SampleData'
}));
The Map<String, String> that holds field names and their values:
  • firstname→"SampleData"
  • lastname→"SampleData"
  • The keys ('firstname','lastname') should match the merge fields defined in your Conga template.
  • The JSON.serialize(...) calls that serialized JSON string into the jsondata key of our outer mergeData map.
    Important: JSONdata itself is expected as a string in the top-level JSON.
  • You must serialize the inner map first, rather than embedding it directly as a nested JSON object.
  • You can expand this map with as many merge fields as you need—simply add more key-value pairs that match your template fields.

Serializing the Full Merge Payload -

Once you have assembled all parts of mergeData, convert the entire map into a JSON string: mergeRequest.setBody(JSON.serialize(mergeData)); At this point, the request body is a complete, valid JSON object containing legacy options, template info, destinations, and the serialized jsondata string.

Creating an HTTP Instance -

The send method dispatches the request to the Conga Merge API. The body constructed is sent to the /Merge endpoint. The Authorization header ensures our request is authenticated. Conga then processes the request, runs the merge and returns details about the results.

Checking and Logging the Response - System.debug('Merge Response: ' + response.getBody());

After the merge request is sent, you can see what came back. This debug statement prints the full response body to the logs. The response will typically contain:
  • Status or result of the merge.
  • Information about the generated document (location, ID, etc.), depending on the specific API contract.
  • Additional checks can be added here, similar to the auth method:
Additional checks can be added here, similar to the auth method:
  • Check response.getStatusCode() for 2xx to confirm success.

  • Log or handle errors if you receive a 4xx or 5xx code.

Full startMerge() Method Example

Here is the full startMerge() method including everything above.

private static void startMerge() {
    System.debug('Merge process has begun...');
    // Create our HTTP request for the Merge API
    HttpRequest mergeRequest = new HttpRequest();
    // Set the endpoint for the merge call
    mergeRequest.setEndpoint(mergeUrl);
    // Use POST since we are sending a JSON body
    mergeRequest.setMethod('POST');
    // Add the Bearer token and JSON headers
    mergeRequest.setHeader('Authorization', 'Bearer ' + authToken);
    mergeRequest.setHeader('Content-Type', 'application/json');
    mergeRequest.setHeader('Accept', 'application/json');
    // Build the JSON payload
    Map<String, Object> mergeData = new Map<String, Object>();
    // Legacy options (such as output file name)
    mergeData.put('LegacyOptions', new Map<String, String>{
        'OFN' => 'mergingFromCongaDrive'
    });
    // Template source - which template to merge against
    mergeData.put('templateSources', new List<Map<String, String>>{
        new Map<String, String>{
            'integrationName' => 'conga',
            'fileId'          => fileId
        }
    });
    // Destination - where the merged file should be stored
    mergeData.put('destinations', new List<Map<String, String>>{
        new Map<String, String>{
            'integrationName' => 'conga',
            'folderId'        => 'root'
        }
    });
    // Merge field data for the template
    mergeData.put('jsondata', JSON.serialize(new Map<String, String>{
        'firstname' => 'SampleData',
        'lastname'  => 'SampleData'
    }));
    // Serialize the entire payload and set it as the request body
    mergeRequest.setBody(JSON.serialize(mergeData));
    // Send the request and capture the response
    HttpResponse response = new Http().send(mergeRequest);
    // Log the full response for verification and troubleshooting
    System.debug('Merge Response Status Code: ' + response.getStatusCode());
    System.debug('Merge Response Body: ' + response.getBody());
}

Putting It All Together

  • initiateMerge() - is the entry point: it first calls getAuth() to retrieve the bearer token, then calls startMerge() to perform the actual merge.
  • getAuth() - handles all aspects of authentication and populates the authToken.
  • startMerge() - uses that token to build and send a JSON-based merge request containing:
    • Legacy options
    • Template sources
    • Destinations
    • Merge field data
  • From here, you can enhance the solution by:
  • Mapping real Salesforce data into jsondata.
  • Handling success and error conditions more robustly based on response.getStatusCode().
  • Parsing the JSON response to capture the resulting document ID or link and attaching it back to a Salesforce record.