salesforce-appraiser-review.../docs/CLM_INTEGRATION.md

11 KiB

CLM Doc Gen Integration Guide

Status note (2026-04-07): the repo is now standardized on the XML merge path built on AppraiserCasePayloadBuilder and CLMDocGenCallout, using Appraiser_Case_Deficiency__c as the canonical child object. See CURRENT_STATUS.md before using this guide as the sole source of truth.

Overview

This guide explains how to integrate Salesforce with DocuSign CLM to generate Appraiser Review Letters dynamically from Appraiser Case records.


Architecture

Components

  1. Salesforce Objects: Appraiser_Case__c and Appraiser_Case_Deficiency__c
  2. Apex Payload Builder: AppraiserCasePayloadBuilder - transforms SOQL data into CLM merge format
  3. HTTP Callout: CLMDocGenCallout - invokes DocuSign CLM API
  4. CLM Template: DocuSign CLM-hosted template with merge fields and repeat blocks
  5. Flow or Apex Trigger: Orchestrates when/how document generation happens

Data Flow

Appraiser Case (UI/API)
    ↓
Salesforce Apex/Flow
    ↓
AppraiserCasePayloadBuilder.buildPayload()  [builds merge data]
    ↓
CLMDocGenCallout.generateDocument()  [sends to CLM API]
    ↓
DocuSign CLM
    ↓
Generated PDF + Envelope
    ↓
Recipient Email

Setup Steps

1. Configure Named Credentials (Salesforce)

Goal: Store CLM API endpoint and authentication credentials securely.

  1. Go to Setup → Named Credentials → New
  2. Configure:
    • Label: CLMNamedCred
    • URL: https://[your-clm-instance].docusign.com
    • Authentication Protocol: OAuth 2.0
    • Client ID: (from DocuSign CLM admin console)
    • Client Secret: (from DocuSign CLM admin console)
    • Scope: (typically signature)
    • Token Endpoint: https://[your-clm-instance].docusign.com/oauth/token
  3. Save

Alternative: For testing, use a custom Named Credential with API Key auth if available from your CLM admin.

2. Configure Remote Site Settings (Salesforce)

Goal: Whitelist CLM domain for HTTP callouts.

  1. Go to Setup → Remote Site Settings → New
  2. Configure:
    • Remote Site Name: DocuSignCLM
    • Remote Site URL: https://[your-clm-instance].docusign.com
    • Disable Protocol Security: (unchecked for production)
  3. Save

3. Get CLM Template ID

Goal: Identify which CLM template to use for Appraiser Review Letters.

  1. In DocuSign CLM admin console, navigate to Templates
  2. Find or create the Appraiser Review Letter template
  3. Note the Template ID (usually a UUID or numeric string)
  4. Verify the template expects these merge fields:
    • AppraiserCaseNumber (Text)
    • AppraiserFieldReviewDate (Date)
    • PropertyAddress (Text)
    • DeficiencyList[] (Array/Lines table with deficiencyNumber, description, resolution)

Usage Patterns

Pattern 1: Queueable Apex (Automatic/Trigger-Driven)

Scenario: Generate letter automatically from a trigger or process (callouts cannot be made synchronously from triggers — use a queueable)

public class AppraiserCaseDocGenJob implements Queueable, Database.AllowsCallouts {
    private Id caseId;
    private String accountCode;
    private String templateDocHref;
    private String destinationFolderHref;
    private String destinationDocName;

    public AppraiserCaseDocGenJob(Id caseId, String accountCode,
            String templateDocHref, String destinationFolderHref, String destinationDocName) {
        this.caseId = caseId;
        this.accountCode = accountCode;
        this.templateDocHref = templateDocHref;
        this.destinationFolderHref = destinationFolderHref;
        this.destinationDocName = destinationDocName;
    }

    public void execute(QueueableContext ctx) {
        CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
            caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
        );
        if (!response.success) {
            System.debug('CLM Doc Gen failed: ' + response.message);
        }
    }
}

// Enqueue from a trigger:
System.enqueueJob(new AppraiserCaseDocGenJob(
    record.Id,
    'DTC_CLM_Demo',
    letterSettings.defaultTemplateDocumentHref,
    letterSettings.destinationRootFolderHref,
    'Review_' + record.Name + '.docx'
));

Pattern 2: LWC Quick Action (UI-Driven) Implemented

The clmDocGenWorkbench component, launched from the Generate Review Letter quick action, is the current implemented UI path. It calls CLMAdminService to:

  • Browse available accounts and letter types
  • Browse CLM template and destination folders
  • Submit a merge task via generateDocument()
  • Poll task status via getTaskStatus()
  • Attach the generated file to the case via attachGeneratedDocumentToCase()

No additional configuration is needed beyond deploying the metadata and setting up Named Credentials.

Pattern 3: REST API (External System)

Scenario: External system calls Salesforce to generate letter

@RestResource(urlMapping='/appraiser-case-generate-letter')
global class AppraiserCaseDocGenRest {
    @HttpPost
    global static void generateLetter(
        String caseId,
        String accountCode,
        String templateDocHref,
        String destinationFolderHref,
        String destinationDocName
    ) {
        CLMDocGenCallout.CLMDocGenResponse response = CLMAdminService.generateDocument(
            (Id) caseId, templateDocHref, destinationFolderHref, destinationDocName, accountCode
        );
        RestContext.response.statusCode = response.success ? 200 : 400;
        RestContext.response.responseBody = Blob.valueOf(JSON.serialize(response));
    }
}

Payload Structure

AppraiserCasePayloadBuilder output (intermediate JSON)

{
  "AppraiserCaseNumber": "AC-000001",
  "AppraiserFieldReviewDate": "Apr 02, 2026",
  "LetterSentDate": "Apr 09, 2026",
  "FHACaseNumber": "123-4567890",
  "AppraiserName": "Jamie Appraiser",
  "AppraiserSalutation": "Ms.",
  "AppraiserLastName": "Appraiser",
  "AppraiserEmail": "jamie@example.com",
  "AppraiserAddress": "245 Lexington Ave, New York, NY 10016, USA",
  "PropertyAddress": "123 Main St, Denver, CO 80202, USA",
  "DeficiencyList": [
    { "deficiencyNumber": 1, "description": "...", "resolution": "...", "reference": "VC-1" }
  ]
}

CLM API Request (what CLMDocGenCallout sends to /documentxmlmergetasks)

{
  "TemplateDocument": { "Href": "https://.../documents/<template-guid>" },
  "DataXML": "<TemplateFieldData><AppraiserCaseNumber>AC-000001</AppraiserCaseNumber>...<DeficiencyList><Deficiency><Number>1</Number>...</Deficiency></DeficiencyList></TemplateFieldData>",
  "DestinationDocumentName": "Review_AC-000001.docx",
  "DestinationFolder": { "Href": "https://.../folders/<folder-guid>" }
}

CLM API Response (on success)

{
  "Href": "https://apiuatna11.springcm.com/v2/<account-id>/documentxmlmergetasks/<task-guid>",
  "Status": "Queued",
  "Result": { "Href": "https://apiuatna11.springcm.com/v2/<account-id>/documents/<doc-guid>" }
}

The response is persisted to Appraiser_Case__c tracking fields by CLMAdminService.persistDocGenResult().


CLM Template Design

The implementation uses the DocuSign CLM XML merge (documentxmlmergetasks) API, not a Handlebars/template-key approach. Template field tags in the .docx file use CLM's Word merge syntax (typically «FieldName» merge fields or CLM repeat-block markers). Refer to your CLM tenant documentation for the exact syntax.

Flat field example (Word merge field in the .docx):

«AppraiserCaseNumber»   «AppraiserFieldReviewDate»
«PropertyAddress»

Deficiency repeat block — the XML structure sent is:

<DeficiencyList>
  <Deficiency>
    <Number>1</Number>
    <Description>Missing comparable sale adjustment detail.</Description>
    <Resolution>Added adjustment rationale and supporting calculations.</Resolution>
    <Reference>VC-1</Reference>
  </Deficiency>
</DeficiencyList>
<DeficiencyCount>1</DeficiencyCount>

Configure a repeat region in your CLM template over DeficiencyList/Deficiency, binding Number, Description, Resolution, and Reference within the loop.


Testing

Unit Test (Apex)

sf apex run test --test-level RunLocalTests --target-org appraiser-dev

Expected: AppraiserCasePayloadBuilderTest passes all assertions.

Integration Test (Manual)

  1. In Salesforce, create an Appraiser Case with 2-3 sample deficiencies
  2. Run (in Apex Execute):
    String caseId = 'a0wKW000007OIiCYAW';
    Map<String, Object> payload = AppraiserCasePayloadBuilder.buildPayload(caseId);
    System.debug(JSON.serialize(payload));
    
  3. Copy payload output
  4. Verify all fields and DeficiencyList array are populated

CLM Integration Test

  1. Set up Named Credentials and Remote Site Settings (see Setup section)
  2. Configure CLM template ID in CLMDocGenCallout
  3. Run (in Apex Execute):
    String caseId = 'a0wKW000007OIiCYAW';
    String templateId = 'TEMPLATE_123';
    String recipientEmail = 'test@example.com';
    
    CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument(
        caseId, templateId, recipientEmail
    );
    
    System.debug('Success: ' + response.success);
    System.debug('Message: ' + response.message);
    System.debug('Document URL: ' + response.documentUrl);
    
  4. Monitor CLM instance for outbound document delivery

Troubleshooting

"Document generated successfully" but no email received

  • Check recipient email in CLM settings (delivery rules may have delay)
  • Verify Email-to-Sign integration is enabled in CLM
  • Check CLM audit log for delivery status

HTTP 401 Unauthorized (Named Credentials)

  • Verify OAuth token is valid in Named Credentials
  • Refresh token or re-authorize
  • Check OAuth scope matches CLM permissions

"Appraiser Case not found" error

  • Verify record ID is correct
  • Ensure Appraiser_Case__c object permissions are granted to running user

Empty DeficiencyList in generated document

  • Check that related Appraiser_Case_Deficiency__c records exist
  • Verify CLM template correctly references {{DeficiencyList}}
  • Test payload in Apex to confirm array is populated

Performance Notes

  • AppraiserCasePayloadBuilder.buildPayload() runs one query (with related records in subquery)
  • CLMDocGenCallout.generateDocument() performs one HTTP callout (blocks execution ~1-5 seconds)
  • For bulk operations, consider queueable jobs or batch class to manage API rate limits

Next Steps

  1. Deploy Apex classes to org (included in manifest)
  2. Configure Named Credentials with CLM OAuth/API credentials
  3. Add CLM Template ID to CLMDocGenCallout (configurable constant or custom setting)
  4. Build a Flow or Trigger to invoke CLMDocGenCallout
  5. Test end-to-end with sample Appraiser Case records

Last updated: 2026-04-02 Updated to include setup instructions and integration patterns.