Common API Tasks🐈: Parsing an envelope's audit events
Parse audit events in your envelopes' history with the eSignature REST API to find corrections and downloads.
Welcome to another edition of the CAT🐈 (Common API Tasks) blog. This blog series is about giving you all you need to complete small, specific, SDK-supported tasks using one of our APIs. You can find all articles in this series on the Docusign developer blog.
Did you know that Docusign keeps track of any and all activity related to each envelope that is sent in the Docusign Agreement Cloud? For many important reasons, the system keeps a detailed audit trail for each envelope. You can find this information in the web app by selecting the History option (also available in the signing UI). Many important activities in an envelope’s lifecycle are recorded as audit events, including when the envelope was created, sent, opened for viewing, signed, and more. You can get the entire audit trail by using a single API call and then parse it to find useful information.
In this blog post I’ll show code snippets to find out if an envelope was corrected as well as if it was downloaded. This is done by looking over all the events in the envelope’s audit history and searching for the specific events telling us that the envelope was either corrected or downloaded (there are two events for downloading an envelope, depending on whether the user downloaded a ZIP file with all documents, or just downloaded specific documents). If I find the envelope was corrected or downloaded, I’ll report about when it was done and by whom (which user). Note that this is simple code and I didn’t address the possibility that an envelope was corrected or downloaded multiple times. You can enhance this code to deal with more complex situations, as well as look for other events that may interest you.
Important note: This particular API call is resource-intensive and has a performance impact; use it only when needed.
And without further ado, here are the code snippets for our six SDK languages:
C#
// You need to obtain an access token using your chosen authentication flow
var apiClient = new ApiClient(basePath);
apiClient.Configuration.DefaultHeader.Add("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(apiClient);
var audit = envelopesApi.ListAuditEvents(accountId, envelopeId);
foreach (var auditEvent in audit.AuditEvents)
{
bool corrected = false;
bool downloaded = false;
string userName = "";
string logTime= "";
foreach (var auditField in auditEvent.EventFields)
{
if (auditField.Name == "UserName")
{
userName = auditField.Value;
}
else if (auditField.Name == "logTime")
{
logTime = auditField.Value;
}
else if ((auditField.Name == "Action") && (auditField.Value == "Corrected"))
{
corrected = true;
}
else if ((auditField.Name == "Action") && ((auditField.Value == "Printable Copy Delivered") || (auditField.Value == "Archive Delivered")))
{
downloaded = true;
}
}
if (corrected)
{
Console.WriteLine($"Envelope was corrected by {userName} on {logTime}");
}
if (downloaded)
{
Console.WriteLine($"Envelope was downloaded by {userName} on {logTime}");
}
}
Java
// You need to obtain an access token using your chosen authentication flow
Configuration config = new Configuration(new ApiClient(basePath));
config.addDefaultHeader("Authorization", "Bearer " + accessToken);
EnvelopesApi envelopesApi = new EnvelopesApi(config);
EnvelopeAuditEventResponse audit = envelopesApi.ListAuditEvents(accountId, envelopeId);
for (EnvelopeAuditEvent auditEvent : audit.getAuditEvents())
{
boolean corrected = false;
boolean downloaded = false;
string userName = "";
string logTime= "";
for (NameValue auditField : auditEvent.getEventFields())
{
if (auditField.getName() == "UserName")
{
userName = auditField.getValue();
}
else if (auditField.getName() == "logTime")
{
logTime = auditField.getValue();
}
else if ((auditField.getName() == "Action") && (auditField.getValue() == "Corrected"))
{
corrected = true;
}
else if ((auditField.getName() == "Action") && ((auditField.getValue() == "Printable Copy Delivered") || (auditField.getValue() == "Archive Delivered")))
{
downloaded = true;
}
}
if (corrected)
{
System.out.println("Envelope was corrected by " + userName + " on " + logTime);
}
if (downloaded)
{
System.out.println("Envelope was downloaded by " + userName + " on " + logTime);
}
}
Node.js
// You need to obtain an access token using your chosen authentication flow
let dsApiClient = new docusign.ApiClient();
dsApiClient.setBasePath(basePath);
dsApiClient.addDefaultHeader('Authorization', 'Bearer ' + accessToken);
let envelopesApi = new docusign.EnvelopesApi(dsApiClient);
let audit = envelopesApi.listAuditEvents(accountId, envelopeId);
audit.auditEvents.forEach (auditEvent =>
{
let corrected = false;
let downloaded = false;
auditEvent.eventFields.forEach(auditField =>
{
if (auditField.name === 'UserName')
{
userName = auditField.Value;
}
else if (auditField.name === 'logTime')
{
logTime = auditField.value;
}
else if ((auditField.name === 'Action') && (auditField.value === 'Corrected'))
{
corrected = true;
}
else if ((auditField.name === 'Action') && ((auditField.value === 'Printable Copy Delivered') || (auditField.value === 'Archive Delivered')))
{
downloaded = true;
});
});
if (corrected)
{
console.log('Envelope was corrected by ' + userName + ' on ' + logTime);
}
if (downloaded)
{
console.log('Envelope was downloaded by ' + userName + ' on ' + logTime);
}
}
PHP
# You 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);
$audit = $envelopes_api->listAuditEvents($account_id, $envelope_id);
$audit_events = $audit->getAuditEvents();
foreach ($audit_event as $audit_events)
{
$corrected = false;
$downloaded = false;
$audit_fields = $audit_event->getEventFields();
foreach ($audit_field as $audit_fields)
{
if ($audit_field->getName() == 'UserName')
{
$user_name = $audit_field->getValue();
}
elseif ($audit_field->getName() == 'logTime')
{
$log_time = $audit_field->getValue();
}
elseif (($audit_field->getName() == 'Action') && ($audit_field->getValue() == 'Corrected'))
{
$corrected = true;
}
elseif (($audit_field->getName() == 'Action') && (($audit_field->getValue() == 'Printable Copy Delivered') || ($audit_field->getValue() == 'Archive Delivered')))
{
$downloaded = true;
}
}
if ($corrected)
{
printf('Envelope was corrected by ' + $user_name + ' on ' + $log_time);
}
if ($downloaded)
{
console.log('Envelope was downloaded by ' + $user_bame + ' on ' + $log_time);
}
}
Python
# You need to obtain an access token using your chosen authentication flow
api_client = ApiClient()
api_client.host = base_path
api_client.set_default_header('Authorization', 'Bearer ' + access_token)
envelopes_api = EnvelopesApi(api_client)
audit = envelopes_api.list_audit_events(account_id, envelope_id)
for audit_event in audit.audit_events:
corrected = false
downloaded = false
for audit_field in audit_fields.event_fields:
if audit_field.name == 'UserName' :
user_name = audit_field.value
elif audit_field.name == 'logTime' :
log_time = audit_field.value
elif (audit_field.name == 'Action') && (audit_field.value == 'Corrected') :
corrected = true
elif (audit_field.name == 'Action') && ((audit_field.value == 'Printable Copy Delivered') || (audit_field.value == 'Archive Delivered')) :
downloaded = true
if corrected :
print('Envelope was corrected by ' + user_name + ' on ' + log_time)
if downloaded :
print('Envelope was downloaded by ' + user_bame + ' on ' + log_time)
Ruby
# You 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
audit = envelopes_api.list_audit_events(account_id, envelope_id)
audit.audit_events.each do |audit_event|
{
corrected = false
downloaded = false
audit_fields.event_fields.each do |audit_field|
{
if audit_field.name == 'UserName'
user_name = audit_field.value
elsif audit_field.name == 'logTime'
log_time = audit_field.value
elsif (audit_field.name == 'Action') && (audit_field.value == 'Corrected') :
corrected = true
elsif (audit_field.name == 'Action') && ((audit_field.value == 'Printable Copy Delivered') || (audit_field.value == 'Archive Delivered'))
downloaded = true
}
if corrected
printf('Envelope was corrected by ' + user_name + ' on ' + log_time)
if downloaded :
printf('Envelope was downloaded by ' + user_bame + ' on ' + log_time)
}
That’s it for today’s edition... I hope you found it useful. 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