Common API Tasks🐈: Locking and unlocking envelopes
This blog series is focused on simple API tasks, yet useful pieces of functionality that can be accomplished using one of the Docusign APIs.
Welcome to another post of the Common API Tasks blog series for developers! This blog series is focused on simple, yet useful pieces of functionality that can be accomplished using one of the Docusign APIs. In past posts I helped you with things like how to void an envelope or how to retrieve tab data. In my last post, I showed you how you can add more users to a Docusign account using the eSignature REST API. In this issue I’ll be showing you a very useful technique to make your applications more robust by locking and unlocking envelopes as needed.
As developers who use various systems of source control, I’m sure you’re familiar with the concept of merge conflicts: two (or more) developers making changes to the same file and ending up with the wrong version that someone has to go and resolve.
Similarly, in Docusign, when you have more than one user (or sometimes the same user using two instances of your application) accessing the system and trying to make changes to the same envelope, you may run into trouble.
To help developers with this problem, the eSignature REST API provides a mechanism to lock envelopes such that only a particular user of a particular integration can modify them. While the envelope is locked, any other requests to modify it are denied and result in an error. Note that opening an envelope for signing is considered modifying it, even if you don’t actually sign it. That is because the Docusign system records each interaction with the envelope and changes the certificate of completion, which is part of the envelope.
In this blog post, I’ll cover how to lock an envelope, how to check if an envelope is locked and how to unlock the envelope. The code snippets that I show do the following:
Check if envelope is locked or not
If it is unlocked, lock it
If it is locked, unlock it
When you lock an envelope, you have to provide some information, including which app is locking the envelope and the duration of the lock. You may also provide a password. That is useful if you are locking a template and want to make sure that it is not changed.
Your application gets back a lockToken, which must later be used to unlock the envelope using an HttpHeader. You cannot unlock an envelope without this lockToken (the lock will expire when the LockDurationInSeconds has passed).
OK, so let’s get down to some code...
C#
// You will need to obtain an accessToken using your chosen authentication flow
var config = new Configuration(new ApiClient(basePath));
config.AddDefaultHeader("Authorization", "Bearer " + accessToken);
var envelopesApi = new EnvelopesApi(config);
try
{
LockInformation lockInfo = envelopesApi.GetLock(accountId, envelopeId);
// check if this app locked it
if (lockInfo.LockedByApp == "C.A.T. App")
{
// add a header with the LockToken to ensure this app has the right to unlock
string LockHeader = $"{{\"lockToken\":\"{lockInfo.LockToken}\"}}";
envelopesApi.Configuration.AddDefaultHeader("X-Docusign-Edit", LockHeader);
envelopesApi.DeleteLock(accountId, envelopeId);
}
}
catch (ApiException exp)
{
// GetLock would throw an ApiException with error 404 if the envelope is unlocked
if (exp.ErrorCode == 404)
{
var lockRequest = new LockRequest
{
LockedByApp = "C.A.T. App",
LockDurationInSeconds = "300",
LockType = "edit"
};
envelopesApi.CreateLock(accountId, envelopeId, lockRequest);
}
}
Java
// You will need to obtain an accessToken using your chosen authentication flow
Configuration config = new Configuration(new ApiClient(basePath));
config.addDefaultHeader("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(config);
try
{
LockInformation lockInfo = envelopesApi.getLock(accountId, envelopeId);
// check if this app locked it
if (lockInfo.getLockedByApp() == "C.A.T. App")
{
// add a header with the LockToken to ensure this app has the right to unlock
String LockHeader = String.Format("{{\"lockToken\":\"%s\"}}",
lockInformation.getLockToken());
envelopesApi.getConfiguration().addDefaultHeader("X-Docusign-Edit", LockHeader);
envelopesApi.deleteLock(accountId, envelopeId);
}
}
catch (ApiException exp)
{
// GetLock would throw an ApiException with error 404 if the envelope is unlocked
if (exp.getCode() == 404)
{
LockRequest lockRequest = new LockRequest();
lockRequest.setLockedByApp("C.A.T. App");
lockRequest.setLockDurationInSeconds("300");
lockRequest.setLockType("edit");
envelopesApi.createLock(accountId, envelopeId, lockRequest);
}
}
Node.js
// You will need to obtain an accessToken using your chosen authentication flow
let dsApiClient = new docusign.ApiClient();
dsApiClient.setBasePath(basePath);
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + accessToken);
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
try
{
let lockInfo = envelopesApi.getLock(accountId, envelopeId);
// check if this app locked it
if (lockInfo.lockedByApp === 'C.A.T. App')
{
// add a header with the LockToken to ensure this app has the right to unlock
let lockHeader = '{{"lockToken":"${lockInfo.lockToken}"}}';
envelopesApi.configuration.addDefaultHeader('X-Docusign-Edit', lockHeader);
envelopesApi.deleteLock(accountId, envelopeId);
}
}
catch (exp)
{
// GetLock would throw an ApiException with error 404 if the envelope is unlocked
if (exp.status == 404)
{
let lockRequest = new docusign.LockRequest.constructFromObject({
LockedByApp : 'C.A.T. App',
lockDurationInSeconds : '300',
lockType : 'edit' });
envelopesApi.createLock(accountId, envelopeId, lockRequest);
}
}
PHP
# You will need to obtain an $access_token using your chosen authentication flow
$api_client = new \Docusign\eSign\client\ApiClient($base_path);
$config = new \Docusign\eSign\Model\Configuration($api_client);
$config->addDefaultHeader('Authorization', 'Bearer ' + $access_token);
$envelopes_api = new \Docusign\Api\EnvelopesApi($config);
try
{
$lock_info = $envelopes_api->getLock($account_id, $envelope_id);
# check if this app locked it
if ($lock_info->getLockedByApp() == 'C.A.T. App')
{
# add a header with the LockToken to ensure this app has the right to unlock
$lock_header = sprintf('{{"lockToken":"%s"}}', $lock_info->getLockToken());
$envelopes_api->configuration->addDefaultHeader('X-Docusign-Edit', $lock_header);
$envelopes_api->deleteLock(accountId, envelopeId);
}
}
catch (ApiException $exp)
{
# GetLock would throw an ApiException with error 404 if the envelope is unlocked
if ($exp->getCode() == 404)
{
$lock_request = new \Docusign\eSign\Model\lockRequest();
$lock_request->setLockedByApp('C.A.T. App');
$lock_request->setlockDurationInSeconds('300');
$lock_request->setlockType('edit');
$envelopes_api->createLock($account_id, $envelope_id, $lock_request);
}
}
Python
# You will need to obtain an access_token using your chosen authentication flow
api_client = ApiClient()
api_client.set_default_header('Authorization', 'Bearer ' + access_token)
envelopes_api = EnvelopesApi(config)
try:
lock_info = envelopes_api.get_lock(account_id, envelope_id)
# check if this app locked it
if lockInfo.locked_by_app == 'C.A.T. App':
# add a header with the LockToken to ensure this app has the right to unlock
lock_header = '{{"lockToken":"{0}"}}'.format(lock_info.lock_token)
envelopes_api.configuration.set_default_header('X-Docusign-Edit', lock_header)
envelopes_api.delete_lock(account_id, envelope_id)
except ApiException as exp:
# GetLock would throw an ApiException with error 404 if the envelope is unlocked
if exp.status == 404:
lock_request = LockRequest()
lock_request.locked_by_app = 'C.A.T. App'
lock_request.lock_duration_in_seconds = '300'
lock_request.lock_type = 'edit'
envelopes_api.create_lock(account_id, envelope_id, lock_request)
Ruby
# You will need to obtain an access_token using your chosen authentication flow
config = DocuSign_eSign::Configuration.new
config.host = base_path
api_client = DocuSign_eSign::ApiClient.new config
api_client.DefaultHeader['Authorization'] = 'Bearer ' + access_token
envelopes_api = DocuSign_eSign::EnvelopesApi.new api_client
begin
lock_info = envelopes_api.get_lock(account_id, envelope_id)
# check if this app locked it
if lockInfo.locked_by_app == 'C.A.T. App'
# add a header with the LockToken to ensure this app has the right to unlock
lock_header = '{{"lockToken":"%s"}}' % lock_info.lock_token
envelopes_api.Configuration..DefaultHeader['X-Docusign-Edit'] = lock_header
envelopes_api.delete_lock(account_id, envelope_id)
end
rescue DocuSign_eSign::ApiError => exp
# GetLock would throw an ApiException with error 404 if the envelope is unlocked
if exp.status == 404
lock_request = DocuSign_eSign::LockRequest.new
lock_request.locked_by_app = 'C.A.T. App'
lock_request.lock_duration_in_seconds = '300'
lock_request.lock_type = 'edit'
envelopes_api.create_lock(account_id, envelope_id, lock_request)
end
end
I hope you found this useful. As usual, if you have any questions, comments, or suggestions for topics for future Common API Tasks posts, feel free to email me. Until next time...
Additional resources
Inbar Gazit has been with Docusign since 2013 in various engineering roles. Since 2019 he has focused on developer content. Inbar works on code examples including the launchers, available on GitHub in eight languages, and helps build sample apps showcasing the various Docusign APIs. He is also active on StackOverflow, answering your questions. Inbar can be reached at inbar.gazit@docusign.com.
Related posts