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

648 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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
```http
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)
```json
{
"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)
```json
{
"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)
```json
{
"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)
```json
{
"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)
```json
{
"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
// 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**:
```http
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**:
```json
{
"access_token": "eyJ0eXAiOiJNVCIsImFsZyI...",
"token_type": "Bearer",
"expires_in": 3600
}
```
#### Step 3: Use Access Token
```http
Authorization: Bearer eyJ0eXAiOiJNVCIsImFsZyI...
```
### 4.2 OAuth2 Authorization Code
**User-based authentication** (not recommended for this use case)
See [Docusign OAuth2 documentation](https://developers.docusign.com/platform/auth/authcode/) 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**:
```http
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 50
X-RateLimit-Reset: 1614358800
```
**Error when limit exceeded**:
```json
{
"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
```json
{
"compositeTemplates": [
{
"inlineTemplates": [
{
"customFields": {
"textCustomFields": [
{
"name": "SalesforceRecordId",
"value": "0018V00000ABC123",
"show": "false",
"required": "false"
}
]
}
}
]
}
]
}
```
### 6.2 List Custom Fields
```json
{
"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):
```json
{
"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**:
```http
GET /restapi/v2.1/accounts/{accountId}/templates?count=100&order=name&order_by=asc
```
**Response**:
```json
{
"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**:
```http
GET /restapi/v2.1/accounts/{accountId}/templates/{templateId}
```
**Response**:
```json
{
"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
```apex
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**:
```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.**
```apex
// ============================================================
// 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**:
```apex
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
```apex
// 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()`
---
## 12. Reference Links
- [Docusign REST API Reference](https://developers.docusign.com/docs/esign-rest-api/reference/)
- [Composite Templates Guide](https://developers.docusign.com/docs/esign-rest-api/how-to/request-signature-composite-template/)
- [JWT Authentication](https://developers.docusign.com/platform/auth/jwt/)
- [Salesforce Named Credentials](https://help.salesforce.com/s/articleView?id=sf.named_credentials_about.htm)
- [Salesforce HTTP Callouts](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_http_httprequest.htm)
---
**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 |