16 KiB
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": "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"
}
]
}
]
}
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 dfsle.Recipient.withSmsDelivery(phone)
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
emailfield 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.3 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.4 Apex Usage Pattern
// Resolve email from Contact record
String recipientEmail = contact.Email;
// Substitute placeholder when email is blank and SMS phone is provided
if (String.isBlank(recipientEmail) && String.isNotBlank(smsPhone)) {
recipientEmail = 'placeholder_email@docusign.com';
}
// 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.5 Flow V4 Integration
In Docusign_Envelope_Templates_V4, the flow checks the recipient contact's email before presenting the send screen:
Get_Recipient_Contact— queries the Contact linked toDocusign_Recipient_1__cIs_Recipient_Email_Blank— if email is null or empty, routes to the phone collection screen; otherwise proceeds normallySMS_Phone_Screen— collects the mobile number (required text field); stores result in therecipientSmsPhoneflow variableSend_Composite_Envelopeaction — receivesrecipientSmsPhoneas an input; when non-blank the Apex layer applieswithSmsDelivery()
12. Reference Links
- Docusign REST API Reference
- Composite Templates Guide
- JWT Authentication
- Salesforce Named Credentials
- Salesforce HTTP Callouts
Document Version: 1.2
Last Updated: March 13, 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 |