<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="https://community.appian.com/cfs-file/__key/system/syndication/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign</link><description /><dc:language>en-US</dc:language><generator>Telligent Community 12</generator><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign</link><pubDate>Thu, 22 Aug 2024 15:13:31 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>Appian Max Team</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Current Revision posted to Guide by Appian Max Team on 8/22/2024 3:13:31 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;p&gt;There are three common methods for setting up authentication and authorization between Appian and DocuSign.&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d940"&gt;1. Service Account Integration (JWT Grant)&lt;/h3&gt;
&lt;p&gt;This method uses a single service account DocuSign user. The integration calls to DocuSign are made as this service account user. The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account &lt;/a&gt;with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h4&gt;DocuSign Setup Steps for Demo Environment&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Login to &lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Navigate to the &lt;/span&gt;&lt;b&gt;Settings &lt;/b&gt;&lt;span style="font-weight:400;"&gt;tab.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Click on &lt;strong&gt;Apps and Keys&lt;/strong&gt; (under Integrations in the left navigation).&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-00-46/docusign_5F00_1.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-00-46/Screenshot2.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Click &lt;b&gt;Add App / Integration Key.&lt;/b&gt;&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/640x480/__key/communityserver-wikis-components-files/00-00-00-00-46/Screenshot-3.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Add an appropriate &lt;strong&gt;App Name&lt;/strong&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Under &lt;b&gt;Authentication&lt;/b&gt;, select Yes for the question on whether your application can securely store a client secret. (Responding No to this question also works for JWT grant as this method uses the RSA private key as opposed to the client secret key used in the Authorization Code grant method).&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1760x1190/__key/communityserver-wikis-components-files/00-00-00-00-46/8484.screenshot_5F00_4.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Under &lt;strong&gt;Service Integration&lt;/strong&gt;, click &lt;strong&gt;Generate RSA&lt;/strong&gt;&amp;nbsp;and copy the private key to the same location where the information in Step 4 was stored.&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/526x578/__key/communityserver-wikis-components-files/00-00-00-00-46/Screenshot-5.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Appian Setup Steps&lt;/h4&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Create a &lt;strong&gt;Connected System&lt;/strong&gt; using proper naming conventions.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;DocuSign&lt;/strong&gt;.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Add an appropriate name and description.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Authentication&lt;/strong&gt;, select &lt;strong&gt;JWT Grant&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Paste the &lt;strong&gt;Instance URL&lt;/strong&gt; (Account&amp;rsquo;s Base URI), the &lt;strong&gt;API Account ID&lt;/strong&gt;, &lt;strong&gt;API Username&lt;/strong&gt;, &lt;strong&gt;Private RSA Key&lt;/strong&gt;, and &lt;strong&gt;Integration Key&lt;/strong&gt;.
&lt;div class="callout-box callout-info"&gt;For the private key, the copied text needs to include &amp;ldquo; -----BEGIN RSA PRIVATE KEY----- &amp;rdquo; at the beginning and &amp;ldquo; ----- END RSA PRIVATE KEY----- &amp;rdquo; at the end.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;TEST CONNECTION&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When you get a Connection successful alert, click &lt;strong&gt;CREATE&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="per_user_authorization"&gt;2. Per User Authorization (Method 1) - Authorization Code Grant&lt;/h3&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h4 id="mcetoc_1i5oh6d941"&gt;DocuSign Setup Steps for Demo Environment&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Follow steps 1-7 from the Basic Authentication section above.&lt;/li&gt;
&lt;li&gt;Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="max-height:880px;max-width:595px;" alt=" " src="/resized-image/__size/1190x1760/__key/communityserver-wikis-components-files/00-00-00-00-46/8371.secret_5F00_keys_5F00_1.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="max-height:460px;max-width:1114px;" alt=" " src="/resized-image/__size/2228x920/__key/communityserver-wikis-components-files/00-00-00-00-46/Screenshot6.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="mcetoc_1i5oh6d942"&gt;Appian Setup Steps&lt;/h4&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/li&gt;
&lt;li&gt;Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/li&gt;
&lt;li&gt;When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="mcetoc_1i5qp205v0"&gt;3. Per User Authorization (Method 2) - JWT Grant with Organizational Consent to Act on Behalf of All Users&lt;/h3&gt;
&lt;p&gt;As in method 1, this method also uses each individual user&amp;rsquo;s Docusign account to make the integration calls, however the user is not required to manually authorize Appian to act on their behalf. A DocuSign admin provides organizational consent for all users. This method requires using the JWT Tools plugin to accomplish the generation of access tokens and cannot use the DocuSign connected system for integrations.&lt;/p&gt;
&lt;p&gt;This approach is often paired with the Service Account Integration method such that certain calls (Send Envelope) use the JWT Tools plugin and others (Download Document) use the Appian Connected System.&lt;/p&gt;
&lt;h4&gt;Docusign Setup&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Update the account settings on DocuSign by following these steps.&lt;/li&gt;
&lt;li&gt;Follow the steps to implement JWT Grant from the DocuSign documentation.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Appian Setup&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Download &lt;/span&gt;&lt;a href="/b/appmarket/posts/jwt-web-token-tools"&gt;&lt;span style="font-weight:400;"&gt;JWT Plugin&lt;/span&gt;&lt;/a&gt;&lt;span style="font-weight:400;"&gt; from the app market.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Create a third party credential key via the Admin Console (Admin Console -&amp;gt; Third Party Credentials -&amp;gt; Create).&lt;/span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;Name&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: Required field, select a unique easy-to-use name.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Key&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: Appian will auto generate it from the name.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Description&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: Optional field, enter an appropriate description.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Plug-ins List&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: Optional field, type &amp;ldquo;&lt;/span&gt;&lt;b&gt;JWT&lt;/b&gt;&lt;span style="font-weight:400;"&gt;&amp;rdquo; (should show up to select).&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;&lt;b&gt;Credentials&lt;/b&gt;: Optional field, add two fields with the following details.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Enter &lt;/span&gt;&lt;b&gt;appianPrivateKey &lt;/b&gt;&lt;span style="font-weight:400;"&gt;as Field Name and value as the DocuSign Admin Account&amp;rsquo;s generated &lt;/span&gt;&lt;b&gt;Private RSA Key&lt;/b&gt;&lt;span style="font-weight:400;"&gt; (note: remember to copy the entire &amp;mdash;begin RSA private key&amp;mdash; to &amp;mdash;end RSA private key). Check the &lt;/span&gt;&lt;b&gt;Mask &lt;/b&gt;&lt;span style="font-weight:400;"&gt;box to hide it from the front end.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Enter &lt;/span&gt;&lt;b&gt;appianPrivateKeyPassword &lt;/b&gt;&lt;span style="font-weight:400;"&gt;as Field Name and leave the value empty.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Test Connection: Optional, leave it blank and click &amp;ldquo;&lt;b&gt;Save&lt;/b&gt;&amp;rdquo;.&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x504/__key/communityserver-wikis-components-files/00-00-00-00-46/1803.third_2D00_party_2D00_credentials.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Generate Admin&amp;rsquo;s Access Token.&lt;/span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Create an expression rule to generate the &amp;ldquo;Access Token.&amp;rdquo;&lt;/span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Add a rule input for user ID as this rule will be used to generate JWT for the admin as well as the user to impersonate.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Use function - createdocusignrsajwttoken() provided by the JWT Plug-in.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Note that the plug-in requires you to follow the order of the parameters.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Use guidance from &lt;a href="https://developers.docusign.com/platform/auth/jwt/jwt-get-token/"&gt;DocuSign to generate the JWT&lt;/a&gt;.&amp;nbsp;&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/890x496/__key/communityserver-wikis-components-files/00-00-00-00-46/jwt_5F00_token.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Create an integration to generate the admin access token.&lt;/span&gt;
&lt;ol&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Add a rule input for passing the JWT generated in Step 3a(i)&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Under Request Body select &amp;ldquo;&lt;/span&gt;&lt;b&gt;Content Type&lt;/b&gt;&lt;span style="font-weight:400;"&gt;&amp;rdquo; as Multipart and provide &lt;/span&gt;&lt;b&gt;assertion &lt;/b&gt;&lt;span style="font-weight:400;"&gt;which will the generated Admin JWT and &lt;/span&gt;&lt;b&gt;grant_type&lt;/b&gt;&lt;span style="font-weight:400;"&gt; as &amp;quot;urn:ietf:params:oauth:grant-type:jwt-bearer&amp;quot;&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;For additional guidance, follow the &lt;/span&gt;&lt;a href="https://developers.docusign.com/platform/auth/jwt/jwt-get-token/#:~:text=Step%203.%20Obtain%20the%20access%20token"&gt;&lt;span style="font-weight:400;"&gt;DocuSign documentation&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Parse the access token from the response.&lt;/span&gt;&lt;span style="font-weight:400;"&gt;&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1030x968/__key/communityserver-wikis-components-files/00-00-00-00-46/request_5F00_body.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Generate Sender&amp;rsquo;s Access Token&lt;/span&gt;
&lt;ol&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;The admin&amp;rsquo;s generated token will be used to retrieve the sender&amp;rsquo;s information (as long as they are part of the Organization in DocuSign)&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Create an integration to retrieve user information (&lt;a href="https://developers.docusign.com/platform/auth/jwt/jwt-get-token/#:~:text=Step%205.%20Use%20the%20access%20token%20to%20make%20an%20API%20call"&gt;DocuSign Documentation&lt;/a&gt;) using their email address registered with DocuSign and the admin access token generated in Step 3a(i).&lt;/span&gt;&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/768x1024/__key/communityserver-wikis-components-files/00-00-00-00-46/headers.png" /&gt;&lt;/div&gt;
&lt;ol&gt;
&lt;li style="font-weight:400;"&gt;&lt;b&gt;URL&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: The &amp;ldquo;Account ID&amp;rdquo; will be available in the DocuSign settings, recommended to create a constant to store the value. Note that the URL will vary depending on the environment.&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;b&gt;Query Parameters&lt;/b&gt;&lt;span style="font-weight:400;"&gt;: Add &amp;ldquo;email&amp;rdquo; which will be the user&amp;rsquo;s email address.&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;&lt;b&gt;Headers&lt;/b&gt;: Add &amp;ldquo;Authorization&amp;rdquo; where the value will be (in expression mode) &amp;ldquo;Bearer&amp;rdquo; + the admin&amp;rsquo;s access token.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Parse the &amp;ldquo;userId&amp;rdquo; from the generated response and use it in the rule created in Step 3(a) to retrieve the sender&amp;rsquo;s JWT.&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Use the integration created in Step 3(b) to generate the sender&amp;rsquo;s access token.&lt;/span&gt;
&lt;ol&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;The rule input value will be the sender&amp;rsquo;s generated JWT.&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Parse the access token from the response.&lt;/span&gt;&lt;span style="font-weight:400;"&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;Create integration to send envelope as the user via DocuSign&lt;/span&gt;&lt;span style="font-weight:400;"&gt;&lt;/span&gt;
&lt;ol&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;With the sender&amp;rsquo;s access token, DocuSign integrations can be called to create and send envelopes, etc. Note that we cannot use the out of the box Docusign Connected System for any integrations that need a bearer token.&lt;/span&gt;&lt;/li&gt;
&lt;li style="font-weight:400;"&gt;&lt;span style="font-weight:400;"&gt;In the Authorization Header for the integration, pass the sender&amp;rsquo;s generated access token.&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/742x1024/__key/communityserver-wikis-components-files/00-00-00-00-46/envelope.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d943"&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d944"&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Recipient User Name -&lt;/b&gt; this field needs to have the same value that you specified in the &amp;ldquo;name&amp;rdquo; field while creating the envelope in the Create and Send Envelope operation.&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d945"&gt;&lt;span style="font-weight:400;"&gt;Design Tips&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d946"&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Create an Appian group for APP DocuSign Service Accounts.&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Create an Appian Web API as a POST method.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Sections below will help define the expression for this object.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Give the Appian group viewer rights to the Web API.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Create a Service Account in the Admin Console under Web API Authentication &amp;gt; OAuth 2.0 Clients &amp;gt; Create.&lt;/span&gt;
&lt;div class="callout-box callout-info"&gt;Basic Authentication is possible to use in place of OAuth 2.0, but is not recommended due to poor security and expiring password. OAuth 2.0 is the industry-standard protocol for authorization, and should generally be used when possible.&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;Copy the Client ID, Client Secret, and Token Request Endpoint to a secure location where they can be retrieved, as the secret will not be displayed again in the admin console.&lt;/span&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x480/__key/communityserver-wikis-components-files/00-00-00-00-46/client.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span style="font-weight:400;"&gt;&amp;nbsp;Add the service account to the Appian group. Also ensure that the service group has at least &amp;lsquo;Initiator&amp;rsquo; privileges to the process model called in your Appian Web API. &lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;ol style="font-size:115%;"&gt;
&lt;li&gt;Login to the DocuSign with Admin privileges.&lt;/li&gt;
&lt;li&gt;Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation).
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;Add the setup details including Web API URL.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Choose the data format (Legacy vs REST V2.1). When the Legacy format is chosen, the message from Docusign is an older XML format whereas the REST v2.1 is a newer JSON format that is easier to process, and is the recommended option for Appian Integrations.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x480/__key/communityserver-wikis-components-files/00-00-00-00-46/rest_5F00_legacy.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Select the user envelopes that should trigger the webhook callback. The correct value will depend on the REST API authentication method and customer DocuSign setup.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/620x278/__key/communityserver-wikis-components-files/00-00-00-00-46/associated-users.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Select the events that should trigger the webhook callback.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/484x480/__key/communityserver-wikis-components-files/00-00-00-00-46/trigger_5F00_events.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Check the box to include OAuth.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x612/__key/communityserver-wikis-components-files/00-00-00-00-46/oauth.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;ADD CONFIGURATION&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select the OAUTH 2.0 tab.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x200/__key/communityserver-wikis-components-files/00-00-00-00-46/oauth2.0.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Enter in the Client ID, Client Secret, and Authorization Server URL.
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1024x466/__key/communityserver-wikis-components-files/00-00-00-00-46/client_5F00_id.png" /&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;SAVE&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id="mcetoc_1i5rb8ven0"&gt;Parsing the DocuSign Connect Request - (REST v2.1)&lt;/h3&gt;
&lt;p&gt;The webhook body is JSON formatted and can be accessed with standard dot notation or the index() function. You may extract the status and the envelopeId from the body as shown here:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  local!requestBody:a!fromJson( http!request.body),
  local!envelopeDetails: a!map(
    event: index(local!requestBody, &amp;quot;event&amp;quot;, {}),
    envelopeId: index(
      index(local!requestBody, &amp;quot;data&amp;quot;, {}),
      &amp;quot;envelopeId&amp;quot;,
      {}
    ),
    
  ),
  a!startProcess(
    processModel: cons!VT_PM_RECEIVE_ENVELOPE_STATUS,
    processParameters: { envelopeDetails: local!envelopeDetails,
    requestBody:local!requestBody},
    onSuccess: a!httpResponse(
      statusCode: 200,
      headers: {},
      body: &amp;quot;Appian has received the envelope status and saved it.&amp;quot;
    ),
    onError: a!httpResponse(
      statusCode: 302,
      headers: {
        a!httpHeader(
          &amp;quot;referer&amp;quot;,
          http!request.queryParameters.referer
        )
      },
     
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3 id="mcetoc_1i5oh6d947"&gt;Parsing the DocuSign Connect XML (Legacy)&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: integrations, Platform, Architecture&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/16</link><pubDate>Tue, 23 Apr 2024 13:14:56 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>Appian Max Team</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 16 posted to Guide by Appian Max Team on 4/23/2024 1:14:56 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/2502.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-00-46/chrome_5F00_N4zeqb3usv.jpg" /&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5734.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7801.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5238.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1000x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Design Tips&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/14.png" /&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/15.png" /&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/16.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: integrations, Platform, Architecture&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/15</link><pubDate>Thu, 02 Nov 2023 13:22:45 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 15 posted to Guide by joel.larin on 11/2/2023 1:22:45 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/2502.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-00-46/chrome_5F00_N4zeqb3usv.jpg" /&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5734.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7801.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5238.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1000x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;&lt;span style="font-weight:400;"&gt;Design Tips&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/14.png" /&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/15.png" /&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/16.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: integrations, Platform, Architecture&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/14</link><pubDate>Tue, 31 Oct 2023 19:23:32 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>Kim Day</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 14 posted to Guide by Kim Day on 10/31/2023 7:23:32 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/2502.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-00-46/chrome_5F00_N4zeqb3usv.jpg" /&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5734.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7801.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5238.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1000x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="text-decoration:underline;"&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style="text-decoration:underline;"&gt;&lt;span style="font-weight:400;"&gt;Noteworthy Fields&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;&lt;span style="text-decoration:underline;"&gt;&lt;span style="font-weight:400;"&gt;Design Tips&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/14.png" /&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/15.png" /&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/16.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: integrations, Platform, Architecture&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/13</link><pubDate>Tue, 31 Oct 2023 19:16:01 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>Kim Day</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 13 posted to Guide by Kim Day on 10/31/2023 7:16:01 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/2502.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-00-46/chrome_5F00_N4zeqb3usv.jpg" /&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5734.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7801.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5238.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1000x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;Design Tips&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/14.png" /&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/15.png" /&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/16.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;

&lt;div style="font-size: 90%;"&gt;Tags: integrations, Platform, Architecture&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/12</link><pubDate>Wed, 18 Oct 2023 15:22:54 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>matt.cosenza</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 12 posted to Guide by matt.cosenza on 10/18/2023 3:22:54 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https://demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/2502.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/cfs-file/__key/communityserver-wikis-components-files/00-00-00-00-46/chrome_5F00_N4zeqb3usv.jpg" /&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5734.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7801.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/5238.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/6305.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/1000x240/__key/communityserver-wikis-components-files/00-00-00-00-46/7.png" /&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/8.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;Design Tips&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/9.png" /&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/10.png" /&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/500x240/__key/communityserver-wikis-components-files/00-00-00-00-46/11.png" /&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/12.png" /&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/13.png" /&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/320x240/__key/communityserver-wikis-components-files/00-00-00-00-46/14.png" /&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/15.png" /&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;img style="box-shadow:3px 3px 5px rgba(0, 0, 0, 0.1);" alt=" " src="/resized-image/__size/800x240/__key/communityserver-wikis-components-files/00-00-00-00-46/16.png" /&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/11</link><pubDate>Tue, 17 Oct 2023 17:24:50 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 11 posted to Guide by joel.larin on 10/17/2023 5:24:50 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization"&gt;Oauth Authorization&lt;/h2&gt;
&lt;h3&gt;Oauth 2.0 Authorization Code Grant (End User Authentication&lt;/h3&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/10</link><pubDate>Tue, 17 Oct 2023 17:23:47 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 10 posted to Guide by joel.larin on 10/17/2023 5:23:47 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization_code"&gt;Oauth Authorization Code&lt;/h2&gt;
&lt;h3&gt;Oauth 2.0 Authorization Code Grant (End User Authentication&lt;/h3&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/9</link><pubDate>Tue, 17 Oct 2023 17:17:58 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 9 posted to Guide by joel.larin on 10/17/2023 5:17:58 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_authorization_code"&gt;Oauth Authorization Code&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/8</link><pubDate>Tue, 17 Oct 2023 17:17:36 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 8 posted to Guide by joel.larin on 10/17/2023 5:17:36 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth__authorization_code"&gt;Oauth Authorization Code&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/7</link><pubDate>Tue, 17 Oct 2023 17:12:16 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 7 posted to Guide by joel.larin on 10/17/2023 5:12:16 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_2.0_authorization_code_grant_(end_user_authentication)"&gt;Oauth 2.0 Authorization Code Grant (End User Authentication)&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/6</link><pubDate>Tue, 17 Oct 2023 17:11:50 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 6 posted to Guide by joel.larin on 10/17/2023 5:11:50 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="oauth_2.0_authorization_code_grant_(end_user_authentication)"&gt;Oauth 2.0 Authorization Code Grant (End User Authentication)&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/5</link><pubDate>Tue, 17 Oct 2023 17:10:52 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 5 posted to Guide by joel.larin on 10/17/2023 5:10:52 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_2.0"&gt;Oauth 2.0&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/4</link><pubDate>Tue, 17 Oct 2023 17:06:14 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 4 posted to Guide by joel.larin on 10/17/2023 5:06:14 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_2.0_authorization_code_grant_(end_user_authentication)"&gt;Oauth 2.0 Authorization Code Grant (End User Authentication)&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/3</link><pubDate>Tue, 17 Oct 2023 17:02:53 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>matt.cosenza</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 3 posted to Guide by matt.cosenza on 10/17/2023 5:02:53 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h3 id="envelope"&gt;Envelope&lt;/h3&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h3 id="document"&gt;Document&lt;/h3&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h3 id="signature_seal"&gt;Signature Seal&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h3 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h3&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_2.0_authorization_code_grant_(end_user_authentication)"&gt;Oauth 2.0 Authorization Code Grant (End User Authentication)&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h3 id="create_envelope"&gt;Create Envelope&lt;/h3&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h3 id="signing_documents"&gt;Signing Documents&lt;/h3&gt;
&lt;h4&gt;Remote&lt;/h4&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h4&gt;Embedded&lt;/h4&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Noteworthy Fields&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h4&gt;Design Tips&lt;/h4&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h3 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h3&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h3 id="download_signed_document"&gt;Download Signed Document&lt;/h3&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h3 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h3&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="docusign_connect"&gt;DocuSign Connect&lt;/h3&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/2</link><pubDate>Tue, 17 Oct 2023 16:52:21 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>matt.cosenza</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 2 posted to Guide by matt.cosenza on 10/17/2023 4:52:21 PM&lt;br /&gt;
&lt;div style="margin:8px 16% 8px 8%;"&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="#Key_DocuSign_Concepts"&gt;Key DocuSign Concepts&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="#Connectivity_from_Appian_to_DocuSign"&gt;Connectivity from Appian to DocuSign&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#jwtgrant"&gt;JWT&amp;nbsp;Grant&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#Authorization_Code"&gt;Authorization Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#DocuSign_Integrations"&gt;DocuSign Integrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="#Implementing_Integrations_in_Appian"&gt;Implementing Integrations in Appian&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#Create_Envelope"&gt;Create Envelope&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#Signing_Documents"&gt;Signing Documents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#Receiving_Envelope_Status_Updates"&gt;Receiving Envelope Status Updates&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#Setting_Up_DocuSign_Connect"&gt;Setting Up DocuSign Connect&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#Parsing_the_DocuSign_Connect_XML"&gt;Parsing the DocuSign Connect XML&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="#Download_Signed_Document"&gt;Download Signed Document&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="#Promoting_DocuSign_Configurations_to_Production"&gt;Promoting DocuSign Configurations to Production&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="key_docusign_concepts"&gt;Key DocuSign Concepts&lt;/h2&gt;
&lt;p&gt;DocuSign provides electronic signature technology and digital transaction management through a web app. In the DocuSign lifecycle, the process ends with a signed, voided, or rejected document.&amp;nbsp; Because of this, it&amp;rsquo;s important to understand how DocuSign structures its documents and maintains signature validity. DocuSign uses the concept of envelopes and documents to allow seamless signing experiences while preserving document independence&lt;/p&gt;
&lt;h2 id="envelope"&gt;Envelope&lt;/h2&gt;
&lt;p&gt;An envelope can contain one or more documents, the fields in the document, recipient info, delivery progress, sender information, security and more.&lt;/p&gt;
&lt;h2 id="document"&gt;Document&lt;/h2&gt;
&lt;p&gt;A document is the lowest-level object on which an intact signature seal can be placed. Multiple documents can be added to an envelope.&amp;nbsp; After signing, these documents can then be extracted individually if needed.&lt;/p&gt;
&lt;h2 id="signature_seal"&gt;Signature Seal&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-user-guide-apply-electronic-seals"&gt;Electronic seals&lt;/a&gt; are used to show evidence of origin and integrity of documents. One of the ways DocuSign uses seals is to ensure the validity of an electronic signature on a document and to ensure that no document tampering has been done after signing.&amp;nbsp; If a document is split up or changed in any way after signing, the seals will be broken and the signatures are invalidated. If pages or documents need to be independently extracted post signing, to preserve seal integrity, the items need to be split into &amp;ldquo;documents&amp;rdquo; on the same envelope.&lt;/p&gt;
&lt;h2 id="connectivity_from_appian_to_docusign"&gt;Connectivity from Appian to DocuSign&lt;/h2&gt;
&lt;p&gt;Setup of DocuSign requires admin access on the DocuSign account. For easy production deployment, you will want the sandbox to be configured with an account linked to your Production Account.&lt;/p&gt;
&lt;p&gt;Integration to DocuSign in production requires the promotion of an API key by following &lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt; from each environment. The following guide will highlight setting up a connection for a single Appian environment to send single-document envelopes to a single signer.&lt;/p&gt;
&lt;h2 id="jwt_grant_(docusign_service_account)"&gt;JWT Grant (DocuSign Service Account)&lt;/h2&gt;
&lt;p&gt;The first step necessary is to login to the &lt;a href="https://account-d.docusign.com/"&gt;DocuSign account&lt;/a&gt; with Admin privileges that the client wishes to use for their integration and retrieve some key pieces of information.&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Login to&amp;nbsp;&lt;a href="https://demo.docusign.net/"&gt;https:///demo.docusign.net/&lt;/a&gt; with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on API and Keys (under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Copy the &lt;b&gt;User ID&lt;/b&gt;, &lt;b&gt;API Account ID&lt;/b&gt;, and &lt;b&gt;Account&amp;rsquo;s Base URI&lt;/b&gt; to a location where they&amp;rsquo;ll be easily copied.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;ADD APP / INTEGRATION KEY&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Add an appropriate &lt;b&gt;App Name&lt;/b&gt;, ensuring you keep in mind the number of environments you will be connecting.&lt;/p&gt;
&lt;p&gt;7. Copy the &lt;b&gt;Integration Key&lt;/b&gt; to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;8. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Implicit Grant.&lt;/b&gt;&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Generate an RSA keypair and copy the private key to the same location where the information in Step 4 was stored.&lt;/p&gt;
&lt;p&gt;10. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;11. Follow the &lt;a href="https://developers.docusign.com/platform/auth/consent/obtaining-individual-consent/"&gt;steps&lt;/a&gt; required to obtain individual consent for your application to act on a user&amp;rsquo;s behalf.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Create a &lt;b&gt;Connected System&lt;/b&gt; using proper naming conventions.&lt;/p&gt;
&lt;p&gt;2. Select &lt;b&gt;DocuSign&lt;/b&gt;.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Add an appropriate name and description.&lt;/p&gt;
&lt;p&gt;4. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;JWT Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;5. Paste the &lt;b&gt;Instance URL (Account&amp;rsquo;s Base URI), the API Account ID, API Username, Private RSA Key, and Integration Key&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;6. Click &lt;b&gt;TEST CONNECTION&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;7. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="oauth_2.0_authorization_code_grant_(end_user_authentication)"&gt;Oauth 2.0 Authorization Code Grant (End User Authentication)&lt;/h2&gt;
&lt;p&gt;Rather than using a service account to make the calls from Appian to DocuSign, the user authorizes Appian to make calls to DocuSign on their behalf using their DocuSign account. Please note that this method requires providing the user an &lt;a href="https://docs.appian.com/suite/help/latest/authorization_link_component.html"&gt;authorization link&lt;/a&gt; within an Appian SAIL form before making a call on their behalf. If calls on their behalf fail, catch the error, and again provide the user with an authorization link to reauthorize.&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;DocuSign Setup Steps for Demo Environment&lt;/h3&gt;
&lt;p&gt;1. Follow steps 1-7 from the Basic Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Integration Key&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;3. Add a &lt;b&gt;Secret Key&lt;/b&gt; and copy the value.&lt;/p&gt;
&lt;p&gt;4. Add the &lt;b&gt;[APPIAN_URL]/suite/oauth/callback&lt;/b&gt; URL to the &lt;b&gt;Redirect URIs&lt;/b&gt; list.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;5. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Appian Setup Steps&lt;/h3&gt;
&lt;p&gt;The easiest way to interact with DocuSign in Appian is through the use of a Connected System.&lt;/p&gt;
&lt;p&gt;1. Follow steps 1-3 from the JWT Grant Authentication section above.&lt;/p&gt;
&lt;p&gt;2. Under &lt;b&gt;Authentication&lt;/b&gt;, select &lt;b&gt;Authorization Code Grant&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;3. Paste the &lt;b&gt;Instance URL &lt;/b&gt;(Account&amp;rsquo;s Base URI), the &lt;b&gt;API Account ID&lt;/b&gt;, &lt;b&gt;Integration Key, Secret Key &lt;/b&gt;into the Appian setup page then select the &lt;b&gt;DocuSign Environment&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;4. Click &lt;b&gt;AUTHORIZE &lt;/b&gt;to authorize Appian to make calls on the logged in user&amp;rsquo;s behalf (you may need to enter your DocuSign credentials at this time).&lt;/p&gt;
&lt;p&gt;5. When you get a Connection successful alert, click &lt;b&gt;CREATE&lt;/b&gt;.&lt;/p&gt;
&lt;h2 id="docusign_integrations"&gt;DocuSign Integrations&lt;/h2&gt;
&lt;p&gt;Connectivity can quickly be validated with a &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Accounts/Accounts/get/"&gt;GET Account call&lt;/a&gt;. This call will retrieve the account&amp;rsquo;s basic information but does require having the API Account ID&lt;/p&gt;
&lt;p&gt;There are a number of actions that a developer can perform on a DocuSign envelope and the documents contained within. An introduction to the concepts of DocuSign&amp;rsquo;s Object model can be found on their &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/"&gt;eSignature Object Model Overview&lt;/a&gt;. Users of this guide are encouraged to read through DocuSign&amp;rsquo;s documentation to learn more about what is possible when integrating with DocuSign.&lt;/p&gt;
&lt;h2 id="implementing_integrations_in_appian"&gt;Implementing Integrations in Appian&lt;/h2&gt;
&lt;h2 id="create_envelope"&gt;Create Envelope&lt;/h2&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/docusign-connected-system.html#create-and-send-envelope"&gt;Create and Send Envelope&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/Envelopes/create"&gt;Create Envelope&lt;/a&gt; REST API. The request body is expressionable in Appian and the DocuSign documentation page linked above has great JSON examples of configurations with different numbers of documents, signers, recipients, tabs, etc.&lt;/p&gt;
&lt;p&gt;In Appian, an example expression for a single signer with an embedded signing ceremony might look like this:&lt;/p&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!toJson(
  {
    /*documents: - handled by Appian Integration Object*/
    /*status: - handled by Appian Integration Object*/
    emailSubject: ri!subject,
    recipients: {
      signers: {
        {
          autoNavigation: true,
          clientUserId: ri!signer.username,
          email: ri!signer.email,
          name: ri!signer.fullName,
          recipientId: ri!signer.recipientId,
          recipientSuppliesTabs: false,
          routingOrder: &amp;quot;1&amp;quot;,
          tabs: {
            dateSignedTabs: {
              {
                anchorString: &amp;quot;today_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            },
            initialHereTabs: {
              {
                anchorString: &amp;quot;init_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;init_1_o&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            signHereTabs: {
              {
                anchorString: &amp;quot;sig_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                anchorString: &amp;quot;sig_1_o &amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;true&amp;quot;
              }
            },
            textTabs: {
              {
                tabLabel: &amp;quot;firstText&amp;quot;,
                anchorString: &amp;quot;text_1_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              },
              {
                tabLabel: &amp;quot;secondText&amp;quot;,
                anchorString: &amp;quot;text_2_r&amp;quot;,
                anchorXOffset: &amp;quot;0&amp;quot;,
                anchorYOffset: &amp;quot;0&amp;quot;,
                anchorIgnoreIfNotPresent: &amp;quot;true&amp;quot;,
                anchorUnits: &amp;quot;inches&amp;quot;,
                optional: &amp;quot;false&amp;quot;
              }
            }            
          }
        }
      }
    }
  }
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;clientUserId - &lt;/b&gt;this field should only be populated if the signing ceremony will be embedded in Appian for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipient&lt;/a&gt;. Populate using the Appian username.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;recipientId - &lt;/b&gt;this field needs to be unique for the &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipients/#signer-recipient"&gt;recipients&lt;/a&gt; within the envelope. If there is only one recipient, use the number 1. If there are multiple, use unique integers for each.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;tabs -&lt;/b&gt; this implementation uses the anchor string method (see other tab creation methods &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/tabs"&gt;here&lt;/a&gt; and tab types &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeRecipientTabs/"&gt;here&lt;/a&gt;) for designating input fields for the end user. For example, the document template has transparent white text on a white background of &amp;ldquo;sig_1_r&amp;rdquo; where a signature is required.&lt;/p&gt;
&lt;h2 id="signing_documents"&gt;Signing Documents&lt;/h2&gt;
&lt;h3&gt;Remote&lt;/h3&gt;
&lt;p&gt;If clientUserId is not populated, the signing ceremony will be remote. The user will receive an email from DocuSign to perform the signing ceremony in DocuSign.&lt;/p&gt;
&lt;h3&gt;Embedded&lt;/h3&gt;
&lt;p&gt;If clientUserId is populated, the signing ceremony must be &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/concepts/embedding"&gt;embedded&lt;/a&gt;. The user will not receive an email nor have the option to perform the signing ceremony in DocuSign, as the application is responsible for the embedded signing experience.&lt;/p&gt;
&lt;p&gt;Use the Appian Connected System OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#generate-the-recipient-signing-url"&gt;Generate the Recipient Signing URL&lt;/a&gt; which utilizes DocuSign&amp;rsquo;s &lt;a href="https://developers.docusign.com/docs/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient/"&gt;Create Embedded Recipient&lt;/a&gt; REST API. Since this operation is a POST call and the DocuSign URL must be used within 5 minutes, the appropriate way to trigger this integration call is on button-click within a SAIL interface each time the user opens the form. It should not be called within a process model since the user may close the task and come back more than 5 minutes later. It cannot be called as part of local variable instantiation since it is a POST call and not a GET call. An example implementation might look like this:&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;rule!APP_CMPT_requestBoxLayout(
  label: &amp;quot;Acknowledgement&amp;quot;,
  contents: {
    a!richTextDisplayField(
      label: &amp;quot;Rich Text&amp;quot;,
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: {
        a!richTextItem(
          text: { cons!APP_TXT_DS_ACKNOWLEDGEMENT },
          style: { &amp;quot;EMPHASIS&amp;quot; }
        )
      }
    ),
    a!buttonArrayLayout(
      buttons: {
        a!buttonWidget(
          label: &amp;quot;OK&amp;quot;,
          saveInto: rule!APP_INT_DS_genEmbeddedSigningURL(
            envelopeId: ri!envelopeId,
            signer: ri!signer,
            onSuccess: {
              a!save(
                local!embedUrl,
                index(fv!result, &amp;quot;url&amp;quot;, null)
              )
            },
            onError: {
              a!startProcess(
                processModel: cons!APP_PM_INTEGRATION_ERROR_TASK,
                processParameters: {
                  integrationError: fv!error,
                  integrationName: cons!APP_TXT_DS_GEN_URL_INT_NAME,
                  isRetryError: false,
                  request: = &amp;quot;Generate signing URL for envelope &amp;quot; &amp;amp; ri!envelopeId,
                  requestId: ri!requestId,
                  response: fv!result
                }
              ),
              a!save(local!generateUrlError, fv!error)
            }
          ),
          style: &amp;quot;PRIMARY&amp;quot;
        )
      },
      align: &amp;quot;END&amp;quot;
    )
  },
  showWhen: and(
    rule!GBL_isBlank(local!embedUrl),
    rule!GBL_isEmpty(ri!createEnvelopeError),
    rule!GBL_isEmpty(local!generateUrlError)
  ),
  style: &amp;quot;STANDARD&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;h3&gt;Noteworthy Fields&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Return URL -&lt;/b&gt; this is the URL that shows in the web content field of Appian after the (1) user completes the signature (2) user declines to sign OR (3) embedded DocuSign session times out after 20 minutes of inactivity, which is the DocuSign default. This URL cannot be an Appian URL, therefore the best option is a public URL hosted on the customer network, specifically designed to provide the end user with a useful message after any one of these three events occurs. The single message should cover all three scenarios since it will be displayed regardless of which event occurs.&lt;/p&gt;
&lt;h3&gt;Design Tips&lt;/h3&gt;
&lt;p&gt;The embedding URL can be placed with Appian&amp;rsquo;s &lt;a href="https://docs.appian.com/suite/help/latest/Web_Content_Component.html"&gt;web content component&lt;/a&gt; on a SAIL form. If you provide an Appian submit button on the SAIL form, there is a risk that the user clicks that Appian button before completing the signing ceremony, which requires clicking a &amp;ldquo;Finish&amp;rdquo; button on the embedded form. To reduce this risk, prevent the user from submitting the form until the DocuSign Connect Webhook (see below) has informed Appian that the signing ceremony is complete by either:&lt;/p&gt;
&lt;p&gt;1. Disabling the &amp;ldquo;Continue&amp;rdquo; button in Appian until DocuSign has called the Appian Web API and the application database is updated with a &amp;ldquo;Signed&amp;rdquo; status&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!columnLayout(
  contents: {
    a!richTextDisplayField(
      labelPosition: &amp;quot;COLLAPSED&amp;quot;,
      value: a!richTextItem(
        text: &amp;quot;STEPS&amp;quot;,
        color: &amp;quot;SECONDARY&amp;quot;,
        size: &amp;quot;MEDIUM_PLUS&amp;quot;,
        style: &amp;quot;STRONG&amp;quot;
      )
    ),
    a!forEach(
      items: {
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Sign&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; the document&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Finish&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button at the top&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click this&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Refresh&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button until the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below is enabled&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        ),
        a!richTextDisplayField(
          labelPosition: &amp;quot;COLLAPSED&amp;quot;,
          value: {
            a!richTextItem(
              text: &amp;quot;Click the&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; Continue&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;,
              style: &amp;quot;STRONG&amp;quot;
            ),
            a!richTextItem(
              text: &amp;quot; button below&amp;quot;,
              color: &amp;quot;SECONDARY&amp;quot;,
              size: &amp;quot;MEDIUM&amp;quot;
            )
          }
        )
      },
      expression: {
        a!columnsLayout(
          columns: {
            a!columnLayout(
              contents: a!cardLayout(
                contents: a!richTextDisplayField(
                  labelPosition: &amp;quot;COLLAPSED&amp;quot;,
                  value: a!richTextItem(
                    text: fv!index,
                    color: &amp;quot;SECONDARY&amp;quot;,
                    size: &amp;quot;MEDIUM_PLUS&amp;quot;,
                    style: &amp;quot;STRONG&amp;quot;
                  ),
                  align: &amp;quot;CENTER&amp;quot;
                ),
                style: &amp;quot;STANDARD&amp;quot;
              ),
              width: &amp;quot;EXTRA_NARROW&amp;quot;
            ),
            a!columnLayout(
              contents: a!sideBySideLayout(
                items: {
                  a!sideBySideItem(item: fv!item, width: &amp;quot;MINIMIZE&amp;quot;),
                  a!sideBySideItem(
                    item: a!buttonArrayLayout(
                      buttons: a!buttonWidget(
                        icon: &amp;quot;refresh&amp;quot;,
                        tooltip: &amp;quot;You may need to refresh more than once&amp;quot;,
                        saveInto: [INSERT QUERY HERE],
                        style: &amp;quot;NORMAL&amp;quot;
                      ),
                      marginBelow: &amp;quot;NONE&amp;quot;
                    ),
                    width: &amp;quot;MINIMIZE&amp;quot;,
                    showWhen: fv!index = 3
                  )
                },
                alignVertical: &amp;quot;MIDDLE&amp;quot;
              )
            )
          },
          alignVertical: &amp;quot;MIDDLE&amp;quot;
        )
      }
    )
  },
  width: &amp;quot;MEDIUM&amp;quot;
)&lt;/pre&gt;&lt;/p&gt;
&lt;p&gt;2. If there is no subsequent form to activity chain the user to and the signature is the last step in the workflow, one option is to not provide any Appian buttons at all then when the DocuSign Connect Webhook calls the Appian Web API, start a process model that messages the task form to hit an exception flow that ends the task and process model.&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;h2 id="receiving_envelope_status_updates"&gt;Receiving Envelope Status Updates&lt;/h2&gt;
&lt;p&gt;DocuSign has &lt;a href="https://developers.docusign.com/docs/esign-rest-api/esign101/rules-and-limits/"&gt;API rules&lt;/a&gt; for their web services and the most relevant rule is that apps are limited to one GET status request per unique envelope per 15 minutes. This means that process models should NOT have a node (and SAIL interfaces should not have a local variable) that checks the envelope status in DocuSign directly or regularly.&lt;/p&gt;
&lt;p&gt;Instead, set up &lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt; to call an Appian Web API when a relevant change to an envelope (such as it being signed) has occurred and start an Appian process model to begin post-processing (write the status to the database and download the document) at this time.&lt;/p&gt;
&lt;h3&gt;Setting Up DocuSign Connect&lt;/h3&gt;
&lt;h4&gt;&lt;strong&gt;Appian Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Since DocuSign Connect supports Basic Authentication but neither the username or password can be null, an Appian basic user account with a username and password must be created from DocuSign Connect to use when calling the Appian Web API&lt;/p&gt;
&lt;p&gt;1. Create an Appian group for &lt;b&gt;APP DocuSign Service Accounts&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;2. Create an Appian Web API as a POST method&lt;/p&gt;
&lt;p&gt;3. Sections below will help define the expression for this object&lt;/p&gt;
&lt;p&gt;4. Give the Appian group viewer rights to the Web API&lt;/p&gt;
&lt;p&gt;5. Create a basic user account with username and password (&lt;b&gt;not &lt;/b&gt;an Appian service account &amp;amp; API key)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that the password will expire per the settings in the Appian Admin Console and should be updated regularly to prevent integration failures down the line&lt;/p&gt;
&lt;p&gt;6. Add the basic user account to the group&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;DocuSign Setup&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;1. Login to the DocuSign with Admin privileges.&lt;/p&gt;
&lt;p&gt;2. Navigate to the &lt;b&gt;Settings &lt;/b&gt;tab&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;3. Click on &lt;b&gt;Connect &lt;/b&gt;(under Integrations in the left navigation)&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;4. Select &lt;b&gt;Add Configuration&lt;/b&gt; &amp;gt;&lt;b&gt; Custom&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;5. Add the setup details including Web API URL&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;6. Select the user envelopes that should trigger the webhook callback&lt;/p&gt;
&lt;p&gt;The correct value will depend on the REST API authentication method and customer DocuSign setup&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;7. Select the events that should trigger the webhook callback&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;8. Set up basic authentication with Appian basic user account details&lt;/p&gt;
&lt;div style="margin-bottom:3rem;margin-top:3rem;"&gt;&lt;/div&gt;
&lt;p&gt;9. Click &lt;b&gt;SAVE&lt;/b&gt;.&lt;/p&gt;
&lt;h3&gt;Parsing the DocuSign Connect XML&lt;/h3&gt;
&lt;p&gt;The webhook body contains XML information about the envelope event, including the document ID, envelope ID, and envelope status. To be memory efficient, extract these values directly in the Web API expression rather than saving the XML into process variables.&lt;/p&gt;
&lt;p&gt;While the XML can be configured to include the base64 representation of the signed document, &lt;b&gt;DO NOT&lt;/b&gt; send or extract this value and save it into an Appian local variable or process variable since this will have negative impacts to the Appian memory profile. Instead, kick off a process model that downloads the document using the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; which creates an Appian document in a specified folder, skipping the need to handle the base64 representation in variables.&lt;/p&gt;
&lt;p&gt;If extracting dateTimes out of the XML, make sure to account for the time zone of the value since these can come in the signer&amp;rsquo;s time zone depending on the setup.&lt;/p&gt;
&lt;h4&gt;Using XPath&lt;/h4&gt;
&lt;p&gt;&lt;pre class="ui-code" data-mode="java"&gt;a!localVariables(
  /*Have to remove namespaces from the XML to be able to use xpath snippet easily */
  local!cleanXML: substitute(
    substitute(
      ri!docusignXML,
      &amp;quot; xmlns:xsd=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&amp;quot; xmlns:xsi=&amp;quot;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&amp;quot; xmlns=&amp;quot;&amp;quot;http://www.docusign.net/API/3.0&amp;quot;&amp;quot;&amp;quot;,
      &amp;quot;&amp;quot;
    ),
    &amp;quot; xsi:nil=&amp;quot;&amp;quot;true&amp;quot;&amp;quot; &amp;quot;,
    &amp;quot;&amp;quot;
  ),
  /* Apply the xpath that you&amp;#39;re looking for based on the values provided. Always returns the first one. */
  &amp;#39;type!{urn:com:appian:types:APP}APP_H_DocuSignEventNotification&amp;#39;(
    docusignDocumentId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/DocumentStatuses/DocumentStatus/ID/text()&amp;quot;
    ),
    envelopeId: xpathsnippet(
      local!cleanXML,
      &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/EnvelopeID/text()&amp;quot;
    ),
    docusignStatus: lower(
      xpathsnippet(
        local!cleanXML,
        &amp;quot;/DocuSignEnvelopeInformation/EnvelopeStatus/Status/text()&amp;quot;
      )
    )
  )
)&lt;/pre&gt;&lt;/p&gt;
&lt;h4&gt;Using XML Parser Plugin&lt;/h4&gt;
&lt;p&gt;The xmltojson() &lt;a href="/b/appmarket/posts/xml-parser"&gt;plugin function&lt;/a&gt; can also be used in conjunction with a!fromJson() to turn the XML into an Appian dictionary that can be read using the index() function.&lt;/p&gt;
&lt;h2 id="download_signed_document"&gt;Download Signed Document&lt;/h2&gt;
&lt;p&gt;After the XML has been parsed and the status has been verified as &amp;ldquo;completed&amp;rdquo;, use the Appian OOTB operation to &lt;a href="https://docs.appian.com/suite/help/latest/Connected_System.html#download-document-from-an-envelope"&gt;Download Document from Envelope&lt;/a&gt; and utilize the document as needed within the Appian application.&lt;/p&gt;
&lt;h2 id="promoting_docusign_configurations_to_production"&gt;Promoting DocuSign Configurations to Production&lt;/h2&gt;
&lt;h2 id="docusign_integration_key"&gt;DocuSign Integration Key&lt;/h2&gt;
&lt;p&gt;DocuSign integration keys cannot be created directly in production. The key is instead promoted from the demo environment for the customer account to the production environment for the customer account. This includes an automated API review in the demo environment for which a selected day of at least 20 API calls are reviewed to ensure no API violations. Plan for this process in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://developers.docusign.com/esign-rest-api/guides/go-live-steps"&gt;DocuSign&amp;#39;s Go-Live Steps&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="docusign_connect"&gt;DocuSign Connect&lt;/h2&gt;
&lt;p&gt;The DocuSign Connect setup is done manually for lower environments and production. Plan for these manual steps in the application deployment guide.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://support.docusign.com/en/guides/ndse-admin-guide-connect"&gt;DocuSign Connect&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item><item><title>Integrating with DocuSign</title><link>https://community.appian.com/success/w/guide/3253/integrating-with-docusign/revision/1</link><pubDate>Thu, 31 Aug 2023 18:58:42 GMT</pubDate><guid isPermaLink="false">d3a83456-d57b-489c-a84c-4e8267bb592a:3e5e8ebb-fe08-477d-b6b4-cb152a852392</guid><dc:creator>joel.larin</dc:creator><comments>https://community.appian.com/success/w/guide/3253/integrating-with-docusign#comments</comments><description>Revision 1 posted to Guide by joel.larin on 8/31/2023 6:58:42 PM&lt;br /&gt;
&lt;p&gt;temp&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;
</description></item></channel></rss>