# CLM Doc Gen Integration Guide ## 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: Apex Trigger (Automatic) **Scenario**: Generate letter automatically when Appraiser Case status reaches "Ready for Review" ```apex // In a trigger on Appraiser_Case__c AFTER UPDATE if (oldMap.get(record.Id).Status__c != 'Ready for Review' && record.Status__c == 'Ready for Review') { CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument( record.Id, 'TEMPLATE_ID_FROM_CLM', // e.g., '123456' record.Reviewer_Email__c ); if (!response.success) { // Log error or send notification System.debug('CLM Doc Gen failed: ' + response.message); } } ``` ### Pattern 2: Flow (UI-Driven) **Scenario**: User clicks button to generate letter on-demand 1. Create a Record-Triggered Flow on Appraiser_Case__c 2. Add an Action step: - Action Type: "Apex Action" - Apex Class: Choose custom Apex action that wraps `CLMDocGenCallout.generateDocument()` 3. Pass: - recordId (the Appraiser Case) - templateId (hardcoded or allow user to select) - recipientEmail (from record or user input) 4. On success: Show toast, store document URL on record 5. On error: Show error message ### Pattern 3: REST API (External System) **Scenario**: External system calls Salesforce to generate letter ```apex @RestResource(urlMapping='/appraiser-case-generate-letter') global class AppraiserCaseDocGenRest { @HttpPost global static void generateLetter(String caseId, String templateId, String recipientEmail) { CLMDocGenCallout.CLMDocGenResponse response = CLMDocGenCallout.generateDocument( caseId, templateId, recipientEmail ); // Return response RestContext.response.statusCode = response.success ? 200 : 400; RestContext.response.responseBody = Blob.valueOf(JSON.serialize(response)); } } ``` --- ## Payload Structure ### Input ```json { "AppraiserCaseNumber": "AC-00001", "AppraiserFieldReviewDate": "2026-04-02", "PropertyAddress": "123 Main St, Denver, CO 80202", "DeficiencyList": [ { "deficiencyNumber": 1, "description": "Missing comparable sale adjustment detail.", "resolution": "Added adjustment rationale and supporting calculations." }, { "deficiencyNumber": 2, "description": "Neighborhood trend explanation insufficient.", "resolution": "Expanded market trend narrative with MLS evidence." }, { "deficiencyNumber": 3, "description": "Photo date stamps were not included.", "resolution": "Re-uploaded photos with date metadata and captions." } ] } ``` ### CLM API Request (what CLMDocGenCallout sends) ```json { "templateId": "TEMPLATE_ID_FROM_CLM", "mergeData": { ...payload above... }, "delivery": { "recipientEmail": "reviewer@example.com", "documentName": "AppraiserReviewLetter_1743724800000" }, "metadata": { "salesforceRecordId": "a0wKW000007OIiCYAW", "generatedAt": "2026-04-02T05:27:44Z" } } ``` ### CLM API Response (on success) ```json { "success": true, "documentUrl": "https://clm-instance.docusign.com/documents/ABC123XYZ", "documentId": "DOC-001", "message": "Document generated successfully" } ``` --- ## CLM Template Design ### Template Merge Tags (Handlebars syntax) **Flat fields**: ```handlebars

Case Number: {{AppraiserCaseNumber}}

Review Date: {{AppraiserFieldReviewDate}}

Property: {{PropertyAddress}}

``` **Deficiency repeat block**: ```handlebars {{#each DeficiencyList}} {{/each}}
Deficiency # Description Resolution
{{deficiencyNumber}} {{description}} {{resolution}}
``` **Conditional (if no deficiencies)**: ```handlebars {{#if DeficiencyList.length}} {{else}}

No deficiencies found.

{{/if}} ``` --- ## Testing ### Unit Test (Apex) ```bash 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): ```apex String caseId = 'a0wKW000007OIiCYAW'; Map 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): ```apex 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._