
Integrate Salesforce workflow automation with Docusign Workflow Builder API
Learn how to integrate Docusign Workflow Builder API with Salesforce for automated agreement workflows.
Docusign Workflow Builder, formerly Maestro, streamlines agreement workflows, enabling users to build and deploy tailored, automated processes without writing code. Through the Workflow Builder API, Salesforce developers can create a Flow action. This enables Salesforce users and administrators, who prefer declarative, no-code tools such as Flow, to initiate Workflow Builder workflows directly from Salesforce.
This no-code approach facilitates the creation of complex integrations between Salesforce and Docusign.
This blog post follows our previous post, Configuring Salesforce for scalable and secure Docusign integrations. Building on that post as a foundation, I will show you how to integrate the Docusign Workflow Builder API with Salesforce.
You can learn more in the Workflow Builder API overview.
Configuring named credentials for the Workflow Builder API
Follow the instructions in the first blog until Step 2; then begin the steps below.
Step 3: Create an external credential in Salesforce
In Salesforce Setup, search for and select External Credentials.
Select New External Credential.
Enter a Label (such as
WorkflowBuilderExternalCredential) and Name (WorkflowBuilderExternalCredential).Set Authentication Protocol to OAuth 2.0 and Authentication Flow Type to Browser Flow.
Set Scope to
signature extended aow_manage.Note: Including
aow_manageis required for the Workflow Builder APIFor Authentication Provider, select the OpenID Connect provider created in Step 2 (such as
Docusign).Select Save.
Then create a principal:
Scroll down to Principals and select New.
Enter a Label (such as
DocusignNamedPrincipal).Choose Named Principal or Per User Principal for Identity Type.
Set Scope to
signature extended aow_manage.Note: Including
aow_manageis required for the Workflow Builder APISelect Save.
Finally, grant access:
Create a new Permission Set (for example,
ExternalCredentialPermission).Under External Credential Principal Access, enable the principal you created (for example,
DocusignNamedPrincipal) for your external credential.Assign this permission set to users who need access.
Step 4: Create a named credential linked to the external credential
In Salesforce Setup, search for and select Named Credentials.
Click New Named Credential.
Enter a descriptive Label (for example,
WorkflowBuilderAPI) and a Name (this name will be used in External Services).Enter the Docusign API base URL:
Developer environment:
https://api-d.docusign.com/v1Production:
https://api.docusign.com/v1
In the External Credential field, select the external credential created in Step 3 (
WorkflowBuilderExternalCredential).Select Save.
Step 5: Trigger a workflow using named credentials in Apex
To follow the instructions below, you will need to have a published Workflow Builder workflow that was configured in Docusign with the API call as a start method to trigger it.
Reference the named credential
In your Apex code, use the name of your Named Credential in a callout to call the Workflow Builder API.
Example: Apex code to retrieve a list of all available Workflow Builder workflows. This uses the Workflows: getWorkflowsList method of the Workflow Builder API.
String accountId = '2ec17bee-90f1-xxxx-af85-b1ee3558f9xx';
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:WorkflowBuilderAPI/accounts/' + accountId + '/workflows');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
String responseBody = res.getBody();
// Deserialize into a generic map
Map<String, Object> root = (Map<String, Object>) JSON.deserializeUntyped(responseBody);
// Navigate to data > workflows
if (root.containsKey('data')) {
Map<String, Object> data = (Map<String, Object>) root.get('data');
if (data.containsKey('workflows')) {
List<Object> workflows = (List<Object>) data.get('workflows');
for (Object wfObj : workflows) {
Map<String, Object> wf = (Map<String, Object>) wfObj;
String id = (String) wf.get('id');
String name = (String) wf.get('name');
System.debug('Workflow ID: ' + id);
System.debug('Workflow Name: ' + name);
System.debug('\n');
}
}
}Example: Apex code to retrieve trigger requirements using Workflows: getWorkflowTriggerRequirements for a specific Workflow Builder workflow.
String accountId = '2ec17bee-xxxx-xxxx-xxxx-b1ee3558f967';
String workflowId = '10b50319-xxxx-xxxx-xxxx-f33cb4aabf9e';
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint('callout:WorkflowBuilderAPI/accounts/' + accountId + '/workflows/' + workflowId + '/trigger-requirements');
request.setMethod('GET');
request.setHeader('Content-Type', 'application/json');
HttpResponse response = http.send(request);
if (response.getStatusCode() == 200) {
System.debug(response.getBody());
} else {
System.debug('Error: ' + response.getStatusCode() + ' - ' + response.getBody());
}Then make an API call to Workflows: triggerWorkflow to trigger a new instance of a specified Workflow Builder workflow using the workflow ID and passing the required inputs.
String accountId = '2ec17bee-90f1-xxxx-af85-b1ee3558f9xx';
String workflowId = '0b50319-3002-xxxx-a130-f33cb4aabfxx';
// Build the HTTP request
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:WorkflowBuilderAPI/accounts/' + accountId + '/workflows/' + workflowId + '/actions/trigger');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
// Optional: Add input variables if your workflow requires them
Map<String, Object> payload = new Map<String, Object>{
'instance_name' => 'Send envelope (sales2)',
'trigger_inputs' => new Map<String, Object>{
'client name' => 'Joe Doe',
'client email' => 'example@example.com'
}
};
req.setBody(JSON.serialize(payload));
// Send the request
HttpResponse res = http.send(req);
// Handle response
if (res.getStatusCode() == 202) {
System.debug('Workflow triggered successfully.');
System.debug('Response: ' + res.getBody());
} else {
System.debug('Failed to trigger workflow.');
System.debug('Status: ' + res.getStatusCode());
System.debug('Response: ' + res.getBody());
}Note: In all of these examples, keep API scopes, endpoint paths, and JSON fields (such as aow_manage, /accounts/{accountId}/workflows, /trigger-requirements, /actions/trigger, workflowId, instance_name, trigger_inputs, instance_url, and instance_id) unchanged unless official documentation confirms a change.
Integrating with Salesforce Flow Builder with the Workflow Builder API
With the preceding examples, a Salesforce developer can build a Flow action that enables a Salesforce user or administrator who prefers declarative, no-code tools such as Flow to initiate the Workflow Builder workflow directly from within Salesforce. This delivers a no-code experience, enabling users to construct intricate use cases for integrating Salesforce and Docusign, all without requiring any coding.
The Apex class below demonstrates how to create a Flow action and includes all code examples discussed so far.
Step 1: Create a flow action
public with sharing class WorkflowBuilderAPIService {
// The value must match an existing Named Credential
public static String namedCredintialName = 'WorkflowBuilderAPI';
public class TriggerRequirement {
public String id;
public String name;
public String type;
public Map<String, Object> metadata;
}
public static List<Map<String, String>> getAvailableWorkflowBuilderWorkflows(String accountId, String workflowId) {
List<Map<String, String>> workflowsList = new List<Map<String, String>>();
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:' + namedCredintialName + '/accounts/' + accountId + '/workflows');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
String responseBody = res.getBody();
// Deserialize into a generic map
Map<String, Object> root = (Map<String, Object>) JSON.deserializeUntyped(responseBody);
// Navigate to data > workflows
if (root.containsKey('data')) {
Map<String, Object> data = (Map<String, Object>) root.get('data');
if (data.containsKey('workflows')) {
List<Object> workflows = (List<Object>) data.get('workflows');
for (Object wfObj : workflows) {
Map<String, Object> wf = (Map<String, Object>) wfObj;
Map<String, String> workflow = new Map<String, String>{
'id' => (String) wf.get('id'),
'name' => (String) wf.get('name')
};
workflowsList.add(workflow);
}
}
}
return workflowsList;
}
public static String getTriggerRequirements(String accountId, String workflowId) {
String endpoint = 'callout:' + namedCredintialName + '/accounts/' + accountId + '/workflows/' + workflowId + '/trigger-requirements';
Http http = new Http();
HttpRequest request = new HttpRequest();
request.setEndpoint(endpoint);
request.setMethod('GET');
request.setHeader('Content-Type', 'application/json');
try {
HttpResponse response = http.send(request);
if (response.getStatusCode() == 200) {
// Pretty-print JSON
return formatJson(response.getBody());
} else {
return 'Error: ' + response.getStatusCode() + ' - ' + response.getBody();
}
} catch (Exception e) {
return 'Exception during callout: ' + e.getMessage();
}
}
// Method to trigger the Workflow Builder workflow
// @param inputs (in JSON format)
public static Map<String, String> triggerWorkflow(String accountId, String workflowId, String inputs) {
// Build the HTTP request
Http http = new Http();
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:' + namedCredintialName + '/accounts/' + accountId + '/workflows/' + workflowId + '/actions/trigger');
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setBody(inputs);
// Send the request
HttpResponse res = http.send(req);
// Handle response
if (res.getStatusCode() == 200) {
Map<String, Object> data = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());
Map<String, String> workflowInstance = new Map<String, String>{
'id' => (String) data.get('instance_id'),
'name' => (String) data.get('instance_url')
};
return workflowInstance;
} else {
System.debug('Failed to trigger workflow. Status: ' + res.getStatusCode());
return null;
}
}
// Helper to pretty-print JSON using indentation
private static String formatJson(String rawJson) {
try {
Object parsed = JSON.deserializeUntyped(rawJson);
return JSON.serializePretty(parsed);
} catch (Exception e) {
return 'Invalid JSON: ' + e.getMessage();
}
}
// Wrapper class to receive inputs from Flow
public class TriggerRequest {
@InvocableVariable(required=true)
public String accountId;
@InvocableVariable(required=true)
public String workflowId;
@InvocableVariable(required=true)
public String inputs; // JSON string
}
// Wrapper class to return output to Flow
public class TriggerResponse {
@InvocableVariable
public String status;
@InvocableVariable
public String instanceUrl;
@InvocableVariable
public String instanceId;
}
// Flow-invocable method
@InvocableMethod(
label='Trigger Docusign Workflow',
description='Triggers a workflow in Workflow Builder via API'
)
public static List<TriggerResponse> triggerWorkflow(List<TriggerRequest> requests) {
List<TriggerResponse> responses = new List<TriggerResponse>();
for (TriggerRequest req : requests) {
TriggerResponse res = new TriggerResponse();
try {
Http http = new Http();
HttpRequest httpReq = new HttpRequest();
String endpoint = 'callout:' + namedCredintialName + '/accounts/' + req.accountId + '/workflows/' + req.workflowId + '/actions/trigger';
httpReq.setEndpoint(endpoint);
httpReq.setMethod('POST');
httpReq.setHeader('Content-Type', 'application/json');
httpReq.setBody(req.inputs);
HttpResponse httpRes = http.send(httpReq);
if (httpRes.getStatusCode() == 202) {
Map<String, Object> result = (Map<String, Object>) JSON.deserializeUntyped(httpRes.getBody());
res.status = 'Success';
res.instanceUrl = String.valueOf(result.get('instance_url'));
if (result.containsKey('instance_id')) {
res.instanceId = String.valueOf(result.get('instance_id'));
}
} else {
res.status = 'Error: ' + 'HTTP ' + httpRes.getStatusCode() + ': ' + httpRes.getBody();
}
} catch (Exception e) {
res.status = 'Exception: ' + e.getMessage();
}
responses.add(res);
}
return responses;
}
}Step 2: Create a Flow to trigger a Workflow Builder workflow
For record-triggered flows, it is recommended to use a scheduled path opens in a new tab when invoking the action that initiates the Workflow Builder workflow. This asynchronous approach helps prevent timing issues associated with callouts.
Go to Flow Builder.
Add an Action element.
Search for Trigger Docusign Workflow (the label you defined in the invocable method).
Provide the following inputs:
accountIdworkflowIdinputs(must be a JSON string)
Use the returned values:
statusinstanceUrlinstanceId
If the existing Flow Builder screenshot shows the old label Trigger Maestro Workflow, you can either replace the image or add a note below it. For example:
Note: Maestro is now Workflow Builder. This image may show the previous product name, but the workflow concept still applies.
Conclusion
Integrating Salesforce with the Docusign Workflow Builder API enables advanced automation and workflow management within Salesforce. By configuring external and named credentials, users can securely connect Salesforce to the Workflow Builder API. Using Apex code, developers can trigger Workflow Builder workflows and retrieve workflow information, facilitating seamless integration.
Moreover, by building Salesforce Flow actions, non-developers can leverage these integrations through no-code tools, enhancing efficiency and enabling intricate use cases. This integration empowers organizations to streamline processes, automate agreement workflows, and enhance overall productivity.
Additional resources

Achille joined Docusign in March 2024. He's a skilled software developer and support engineer with past experience at Google and Salesforce.
Related posts
Docusign IAM is the agreement platform your business needs



