salesforce-composite-envelo.../composite-envelope-builder/docs/api-reference.md

18 KiB
Raw Blame History

API Reference

Project: Salesforce Composite Envelope Builder
Version: 1.2
Date: February 23, 2026 (updated March 13, 2026)


1. Docusign REST API Integration

1.1 Base Endpoint

Production:

https://na3.docusign.net/restapi/v2.1

Sandbox:

https://demo.docusign.net/restapi/v2.1

Note: Replace na3 with your account's data center (na2, na3, eu1, etc.)


2. Create Composite Envelope

2.1 HTTP Request

Method: POST
Endpoint: /accounts/{accountId}/envelopes
Content-Type: application/json
Authorization: Bearer {access_token}

2.2 Request Headers

POST /restapi/v2.1/accounts/12345678-abcd-1234-abcd-1234567890ab/envelopes HTTP/1.1
Host: na3.docusign.net
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjY4MTg...
Content-Type: application/json
Accept: application/json

2.3 Request Body (Composite Templates)

Minimum Example (2 templates)

{
  "status": "sent",
  "emailSubject": "Docusign: Please review and sign these forms",
  "compositeTemplates": [
    {
      "compositeTemplateId": "1",
      "serverTemplates": [
        {
          "sequence": "1",
          "templateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      ]
    },
    {
      "compositeTemplateId": "2",
      "serverTemplates": [
        {
          "sequence": "2",
          "templateId": "b2c3d4e5-f6g7-8901-bcde-fg2345678901"
        }
      ]
    }
  ]
}

2.5 Email subject & body composition

The Apex layer composes the outgoing email subject and body when building the envelope. Important rules:

  • Subject: Prefixed with "Docusign: " to make the source clear to recipients. The subject is truncated to 100 characters to satisfy Docusign limits.
  • Body: Consists of a greeting, followed by combined template bodies separated by a visual divider, followed by a sign-off. The system supports English (default) and Spanish; the Flow language input accepts locale codes (e.g. es, es-CO) and common strings like Spanish/Español to select Spanish greetings/signoffs.

Advanced Example (with merge fields)

{
  "status": "sent",
  "emailSubject": "Please review and sign these forms",
  "compositeTemplates": [
    {
      "compositeTemplateId": "1",
      "serverTemplates": [
        {
          "sequence": "1",
          "templateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      ],
      "inlineTemplates": [
        {
          "sequence": "1",
          "customFields": {
            "textCustomFields": [
              {
                "name": "SalesforceRecordId",
                "value": "0018V00000ABC123"
              },
              {
                "name": "CaseNumber",
                "value": "00001234"
              }
            ]
          }
        }
      ]
    }
  ]
}

2.4 Response

Success (201 Created)

{
  "envelopeId": "f9876543-21ab-cdef-0123-456789abcdef",
  "uri": "/envelopes/f9876543-21ab-cdef-0123-456789abcdef",
  "statusDateTime": "2026-02-23T12:34:56.789Z",
  "status": "sent"
}

Error (400 Bad Request)

{
  "errorCode": "INVALID_REQUEST_PARAMETER",
  "message": "The request contained at least one invalid parameter. The template with ID 'invalid-id' does not exist."
}

Error (401 Unauthorized)

{
  "errorCode": "USER_AUTHENTICATION_FAILED",
  "message": "One or both of Username and Password are invalid."
}

3. Composite Template Structure

3.1 Key Concepts

compositeTemplates (array):

  • Each element represents a server template to include in the envelope
  • Order in array determines document order in envelope

compositeTemplateId (string):

  • Unique identifier for this composite template within the request
  • Can be any string (recommend using sequence numbers: "1", "2", "3")

serverTemplates (array):

  • References pre-existing templates in your Docusign account
  • Must include templateId (GUID from Docusign)

sequence (string):

  • Determines document order within the envelope
  • "1" = first document, "2" = second, etc.
  • Important: Use strings, not integers

inlineTemplates (array, optional):

  • Allows runtime override of template values
  • Used for custom fields, recipient data, tabs

3.2 Recipient Merging

Automatic Merge: When multiple templates have recipients with the same roleName, Docusign automatically merges them into a single recipient.

Example:

  • Template A has recipient role: "Signer"
  • Template B has recipient role: "Signer"
  • Result: One recipient signs all documents

Requirements for merge:

  • Exact match on roleName
  • Same recipient routingOrder (signing order)
  • Merge happens automatically, no additional configuration needed

4. Authentication

4.1 JWT (JSON Web Token)

Preferred method for server-to-server integration

Step 1: Generate JWT

// Apex pseudocode
String jwt = generateJWT(
    integrationKey,    // From Docusign Apps & Keys
    userId,            // Docusign user GUID
    rsaPrivateKey,     // RSA private key (PEM format)
    'https://account-d.docusign.com/oauth/auth',  // Sandbox
    3600               // Token expiry (1 hour)
);

Step 2: Exchange JWT for Access Token

Request:

POST /oauth/token HTTP/1.1
Host: account-d.docusign.com
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={jwt}

Response:

{
  "access_token": "eyJ0eXAiOiJNVCIsImFsZyI...",
  "token_type": "Bearer",
  "expires_in": 3600
}

Step 3: Use Access Token

Authorization: Bearer eyJ0eXAiOiJNVCIsImFsZyI...

4.2 OAuth2 Authorization Code

User-based authentication (not recommended for this use case)

See Docusign OAuth2 documentation for details.


5. Error Codes

5.1 Common Error Codes

Error Code HTTP Meaning Resolution
INVALID_REQUEST_PARAMETER 400 Invalid parameter in request Check JSON structure, template IDs
USER_AUTHENTICATION_FAILED 401 Invalid or expired access token Refresh access token
USER_LACKS_PERMISSIONS 403 User doesn't have permission Check Docusign user permissions
RESOURCE_NOT_FOUND 404 Template ID not found Verify template exists in account
DUPLICATE_RESOURCE 409 Duplicate request Check for duplicate envelope
ONESIGNAL_GENERIC_ERROR 500 Docusign server error Retry after delay

5.2 Rate Limits

Hourly limit: Varies by plan (1,000 - 10,000+ API calls/hour)

Response header when nearing limit:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 50
X-RateLimit-Reset: 1614358800

Error when limit exceeded:

{
  "errorCode": "HOURLY_APIINVOCATION_LIMIT_EXCEEDED",
  "message": "The maximum number of hourly API invocations has been exceeded."
}

Mitigation:

  • Implement exponential backoff
  • Cache access tokens (don't generate new token for each request)
  • Batch operations when possible

6. Custom Fields

6.1 Text Custom Fields

Use case: Store Salesforce record ID in envelope

{
  "compositeTemplates": [
    {
      "inlineTemplates": [
        {
          "customFields": {
            "textCustomFields": [
              {
                "name": "SalesforceRecordId",
                "value": "0018V00000ABC123",
                "show": "false",
                "required": "false"
              }
            ]
          }
        }
      ]
    }
  ]
}

6.2 List Custom Fields

{
  "customFields": {
    "listCustomFields": [
      {
        "name": "FormLanguage",
        "value": "English",
        "listItems": ["English", "Spanish"]
      }
    ]
  }
}

7. Webhook Configuration

7.1 Connect Webhook (for document retrieval)

Not required for Phase 1, but useful for future automation.

Endpoint: Configure in Docusign Admin → Connect → Add Configuration

Webhook payload (when envelope completes):

{
  "event": "envelope-completed",
  "apiVersion": "v2.1",
  "uri": "/restapi/v2.1/accounts/123/envelopes/abc",
  "envelopeId": "f9876543-21ab-cdef-0123-456789abcdef",
  "envelopeSummary": {
    "status": "completed",
    "emailSubject": "Please review and sign",
    "completedDateTime": "2026-02-23T14:30:00Z"
  }
}

8. Template Management APIs

8.1 List Templates

Use case: Retrieve template list for Flow dropdown

Request:

GET /restapi/v2.1/accounts/{accountId}/templates?count=100&order=name&order_by=asc

Response:

{
  "resultSetSize": "14",
  "totalSetSize": "14",
  "envelopeTemplates": [
    {
      "templateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "name": "Form A - English",
      "shared": "true",
      "description": "English version of Form A"
    },
    {
      "templateId": "b2c3d4e5-f6g7-8901-bcde-fg2345678901",
      "name": "Form B - English",
      "shared": "true",
      "description": "English version of Form B"
    }
  ]
}

8.2 Get Template Details

Use case: Retrieve template metadata (recipients, tabs)

Request:

GET /restapi/v2.1/accounts/{accountId}/templates/{templateId}

Response:

{
  "templateId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "Form A - English",
  "recipients": {
    "signers": [
      {
        "roleName": "Signer 1",
        "recipientId": "1",
        "routingOrder": "1"
      },
      {
        "roleName": "Signer 2",
        "recipientId": "2",
        "routingOrder": "2"
      }
    ]
  },
  "documents": [
    {
      "documentId": "1",
      "name": "Form_A.pdf",
      "pages": "2"
    }
  ]
}

9. Apex HTTP Callout Example

9.1 Complete Callout

public static String createCompositeEnvelope(String envelopeJSON, String accessToken, String accountId) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('callout:DocusignAPI/accounts/' + accountId + '/envelopes');
    req.setMethod('POST');
    req.setHeader('Authorization', 'Bearer ' + accessToken);
    req.setHeader('Content-Type', 'application/json');
    req.setHeader('Accept', 'application/json');
    req.setBody(envelopeJSON);
    req.setTimeout(120000); // 120 seconds
    
    Http http = new Http();
    HttpResponse res = http.send(req);
    
    if (res.getStatusCode() == 201) {
        Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
        return (String) responseMap.get('envelopeId');
    } else {
        throw new CalloutException('Docusign API error [' + res.getStatusCode() + ']: ' + res.getBody());
    }
}

9.2 Named Credential Configuration

Setup → Named Credentials → New Named Credential

Settings:

  • Label: Docusign API
  • Name: DocusignAPI
  • URL: https://na3.docusign.net/restapi/v2.1
  • Identity Type: Named Principal
  • Authentication Protocol: OAuth 2.0
  • Scope: signature impersonation
  • Token Endpoint: https://account-d.docusign.com/oauth/token (sandbox)
  • JWT Token Exchange: Enabled

Usage in Apex:

req.setEndpoint('callout:DocusignAPI/accounts/' + accountId + '/envelopes');

10. Testing with Postman

10.1 Import Docusign Collection

Docusign provides an official Postman collection:
https://github.com/docusign/postman-collections

10.2 Create Composite Envelope Test

Request:

POST {{baseUrl}}/accounts/{{accountId}}/envelopes
Headers:
  Authorization: Bearer {{accessToken}}
  Content-Type: application/json
Body:
  {
    "status": "sent",
    "emailSubject": "Test Composite Envelope",
    "compositeTemplates": [
      {
        "compositeTemplateId": "1",
        "serverTemplates": [
          {
            "sequence": "1",
            "templateId": "{{templateId1}}"
          }
        ]
      },
      {
        "compositeTemplateId": "2",
        "serverTemplates": [
          {
            "sequence": "2",
            "templateId": "{{templateId2}}"
          }
        ]
      }
    ]
  }

11. SMS Delivery via dfsle Apex Toolkit (v1.2)

11.1 Overview

Rather than calling the Docusign REST API directly for SMS delivery, this project uses the native dfsle Apex Toolkit method dfsle.Recipient.withSmsDelivery(), which is part of the Docusign for Salesforce managed package already installed in the org.

This approach requires no additional REST endpoints, no extra authentication, and no HTTP callouts beyond what the toolkit already handles.

11.2 Salesforce Data Setup Prerequisite

Before SMS delivery can work, the Client Case record must be set up correctly:

Field Requirement
Docusign_Recipient_1__c Must be populated — set to a Contact record
Contact Name Must be populated — used as the recipient's display name in Docusign
Contact Email Must be blank — the flow checks this field to route through the SMS path

⚠️ Important: If Docusign_Recipient_1__c is null (no Contact linked at all), the Apex code skips that recipient entirely and Docusign Recipient #1 will be missing from the envelope. The Contact must exist — only the email needs to be absent.

11.3 Placeholder Email Constant

The Docusign API requires an email field on every recipient even when SMS delivery is configured. When the recipient contact has no email address, the Apex layer substitutes a placeholder automatically — no actual email is sent to this address.

🔧 Configuration: The placeholder address is defined as a single constant in DocusignCompositeEnvelopeBuilder.cls. This is the only place that needs to be updated if the placeholder address ever changes.

// ============================================================
// SMS DELIVERY: Placeholder email used when the primary recipient
// (Docusign Recipient #1) has no email address and SMS delivery is
// requested via recipientSmsPhone.  Docusign requires an email on
// every recipient even when dfsle.Recipient.withSmsDelivery() is used.
// ============================================================
@TestVisible
private static final String SMS_PLACEHOLDER_EMAIL = 'placeholder_email@docusign.com';

Method signature:

dfsle.Recipient withSmsDelivery(String phone)

Parameters:

Parameter Type Description
phone String Mobile phone number in E.164 format (e.g. +15551234567). International numbers must include the country code.

Returns: A new dfsle.Recipient instance with SMS delivery configured (deliverBySms = true).

Important notes:

  • This method sets the delivery method for the signing invitation; it is not a 2FA/authentication method.
  • The Docusign API still requires an email field on every recipient even when SMS delivery is configured. When the recipient contact has no email address, a placeholder (placeholder_email@docusign.com) is substituted automatically by the Apex layer. No actual email is sent to this address.
  • Only applied to Docusign Recipient #1. The Service Coordinator always uses email delivery.

11.4 Invocable Action Parameter

The recipientSmsPhone input parameter on the Send_Composite_Envelope Apex action activates SMS delivery:

Parameter Type Required Description
recipientSmsPhone String No Mobile phone number for SMS delivery. When blank (or not provided), the envelope is sent normally by email. E.164 format preferred: +15551234567.

11.5 Apex Usage Pattern

// Resolve email from Contact record
String recipientEmail = contact.Email;

// Substitute placeholder when email is blank and SMS phone is provided.
// SMS_PLACEHOLDER_EMAIL is a constant in DocusignCompositeEnvelopeBuilder.cls —
// update the constant there if the placeholder address ever needs to change.
if (String.isBlank(recipientEmail) && String.isNotBlank(smsPhone)) {
    recipientEmail = SMS_PLACEHOLDER_EMAIL;
}

// Build recipient using dfsle toolkit
dfsle.Recipient recipient = dfsle.Recipient.fromSource(
    contact.Name,
    recipientEmail,
    null,                          // phone param (not used here)
    'Docusign Recipient #1',       // role name — must match template exactly
    new dfsle.Entity(caseRecordId) // source record for merge fields
);

// Enable SMS delivery when phone is provided
if (String.isNotBlank(smsPhone)) {
    recipient = recipient.withSmsDelivery(smsPhone);
}

11.6 Flow V4 Integration

In Docusign_Envelope_Templates_V4, the flow checks the recipient contact's email before presenting the send screen:

  1. Get_Recipient_Contact — queries the Contact linked to Docusign_Recipient_1__c
  2. Is_Recipient_Email_Blank — if email is null or empty, routes to the phone collection screen; otherwise proceeds normally
  3. SMS_Phone_Screen — collects the mobile number (required text field); stores result in the recipientSmsPhone flow variable
  4. Send_Composite_Envelope action — receives recipientSmsPhone as an input; when non-blank the Apex layer applies withSmsDelivery()


Document Version: 1.2
Last Updated: March 15, 2026
Change Log:

Version Date Summary
1.0 2026-02-23 Initial release
1.1 2026-03-11 No changes (version aligned with design/requirements)
1.2 2026-03-13 Added section 11 — SMS delivery via dfsle.Recipient.withSmsDelivery(); documented recipientSmsPhone parameter; renumbered Reference Links to section 12
1.2 2026-03-15 Added 11.2 Contact setup prerequisite; added 11.3 placeholder email constant callout; renumbered 11.311.5 to 11.411.6; updated code example to reference SMS_PLACEHOLDER_EMAIL constant