# 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| Deficiency # | Description | Resolution |
|---|---|---|
| {{deficiencyNumber}} | {{description}} | {{resolution}} |
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