From the Trenches: Sending a Joint Agreement using the eSignature REST API
Discover Joint Agreements and see how to send a Joint Agreement via the eSignature REST API.
Joint agreements is a Docusign offering that enables organizations to collaborate with their business partners to share a single Docusign envelope, with documents provided by all parties, for their shared consumers to sign in a single Docusign signing session.
With Joint Agreements, an organization (the Custodian) can create a network of partners (Network Partners) in Docusign eSignature who are allowed to share access to envelopes; Network Partners can then add their own documents to these envelopes and designate which of the uploaded documents the Custodian can access. The joint envelope is sent to the consumer with the Custodian designated as a carbon copy envelope recipient who is notified upon completion by the consumer. Thus, Joint Agreements is designed to help network creators (Custodians) seamlessly partner with their business network (Network Partners) and their mutual consumers to provide an improved B2B2C experience for all parties involved.
In this blog, I’ll be primarily covering how to create a Joint Agreement and send it out for signature using our eSignature REST API.
Network creator side (Custodian)
First, using joint agreements requires that a Docusign administrator on an account with the Joint Agreements feature activated must create and configure a Joint Agreements network. I’ll show you what the network configuration looks like in the network creator’s (Custodian’s) account:
I’ve set up a designated recipient that will automatically be included as a carbon copy for any joint agreements sent out via Docusign eSignature by any network partner who joins my network. This inclusion happens via the Set Document Access function; however, when sending a joint agreement via the eSignature REST API, you need to introduce a new API attribute to make this possible.
I’ve also mandated SMS Text Message/Phone Authentication, so the network partner would be required to specify this in the API request for any recipients who will have access to the joint agreement document(s). For more information, see Create Joint Agreements Networks on Docusign Support.
The next step is for the network creator to retrieve and share the network invitation link, the linkConfigurationId
, as well as both the display name and the designated recipient email address with the network partners who intend to join their network and use Joint Agreements. The network partners would need these parameters in their API calls in order to properly create a Joint Agreements envelope. The invitation link can be obtained by the network creator via the Docusign eSignature UI, as well as via the API, using this sample request and response:
HTTPS GET https://accountlink-d.docusign.net/v1/primary_accounts/YOUR_ACCOUNT_ID/link_configurations
for our demo/developer environment, and
HTTPS GET https://accountlink.docusign.net/v1/primary_accounts/YOUR_ACCOUNT_ID/link_configurations
for our production environments.
Scopes required: signature
{
"linkConfigurations": [
{
"linkConfigurationId": "4ae16cc5-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"configurationName": "Joint Agreements Test",
"displayName": "Docusign Joint Agreements Test Account",
"linkInvitationUrl": "https://accountlink-d.docusign.net/invite/xxxxxxxxxxxxxxxxxxxxxxxxx",
"autoApproveInvitationResponses": "False",
"enforceAutoNavigation": "None",
"enforceSignatureFormat": "None",
"enforceDateTimeFormat": "None",
"allowSignWithMobileDevice": "None",
"enableSignerCommentsInEnvelope": "None",
"sendLinkRequestNotification": "SendToAllAdmins",
"pdfFieldHandlingOption": "PrefillAndRecipient",
"recipientAuthRequirements": {
"accessCode": "False",
"phone": "True",
"kba": "False",
"idVerification": "False"
},
"clickwrapId": "",
"clickwrapAgreeEachTime": "True",
"recipientAddress": "A valid recipient on the network creator’s account",
"lastModified": "2024-03-14T01:33:33Z",
"enabled": "True",
"linkedAccountCount": {
"Pending": 0,
"Active": 1
}
}
],
"resultSetSize": "1",
"totalSetSize": "1",
"startPosition": "0",
"endPosition": "0"
}
This endpoint will return all the network configurations set up in the network creator account, each with a unique linkConfigurationId
and a linkInvitationUrl
that you can share with network partners to allow them to join your network and send joint agreements.
Note: This API endpoint only works when executed against the network creator’s Docusign account. If you’re a network partner who has joined a Joint Agreements network, this API call will likely not yield the desired results.
Network partner side (Joint Agreements sender)
With the API attributes obtained from the network creator (custodian), the network partner can make a POST request to create a Joint Agreements envelope. Consider the attributes to use when sending a Joint Agreements envelope:
linkedAccountConfigurationId
: The GUID of the Joint Agreements network configuration that is set up and provided by the network creator. If this attribute is missing from thecarbonCopies
recipient declaration, then the envelope that is created is not considered to be a Joint Agreements envelope.name
: The Display Name of the Joint Agreements network configuration, as provided by the network creator.email
: The email address of the Joint Agreements designated recipient associated with the network configuration, as provided by the Network Creator.excludedDocuments
: An array of document IDs to exclude from the Joint Agreements designated recipient (carbon copy), separated by a comma. Documents that are not specified in this array are shared with the Joint Agreements designated recipient.routingOrder
: Must be set to a high enough value so that the Joint Agreements designated recipient is last in the routing order.
Note: Joint Agreements only supports Docusign REST API v2.1. If you are using REST v2, any API call which references linkedAccountConfigurationId
will not work, and the envelope will not be recognized as a Joint Agreements envelope. It will need to be a REST API v2.1 call. Additionally, the legacy SOAP API is not supported.
This is a sample envelope create payload for the create
call:
{
"status": "sent",
"name": "Test Joint Agreement",
"emailSubject": "Please Docusign Joint Agreement",
"recipients": {
"carbonCopies": [
{
"linkedAccountConfigurationId": "4ae16cc5-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Karan Kaushik",
"email": "emailHere",
"recipientId": "2",
"routingOrder": "2",
"excludedDocuments":[2]
}
],
"signers": [
{
"name": "Bob Example",
"email": "bob@example.com",
"recipientId": "1",
"routingOrder": "1",
"identityVerification": {
"inputOptions": [
{
"name": "phone_number_list",
"phoneNumberList": [
{
"countryCode": "61",
"number": "04123456789"
}
],
"valueType": "PhoneNumberList"
}
],
"steps": null,
"workflowId": "Workflow ID from your account"
},
"tabs": {
"signHereTabs": [
{
"name": "SignHere",
"tabLabel": "SignHere",
"documentId": "1",
"pageNumber": "1",
"xPosition": "75",
"yPosition": "150"
}
],
"initialHereTabs": [
{
"name": "InitialHere",
"tabLabel": "InitialHere",
"documentId": "2",
"pageNumber": "1",
"xPosition": "75",
"yPosition": "150"
}
],
"dateSignedTabs": [
{
"name": "DateSigned",
"tabLabel": "DateSigned",
"documentId": "1",
"pageNumber": "1",
"xPosition": "72",
"yPosition": "200"
},
{
"name": "DateSigned",
"tabLabel": "DateSigned",
"documentId": "2",
"pageNumber": "1",
"xPosition": "72",
"yPosition": "200"
}
]
}
}
]
},
"documents": [
{
"documentId": "1",
"name": "Agreement",
"fileExtension": "docx",
"documentBase64": "base64here"
},
{
"documentId": "2",
"name": "Excluded",
"fileExtension": "docx",
"documentBase64": "Base64Here"
}
]
}
To understand what makes this a Joint Agreement, take a look at the carbon copy recipient definition:
{
"linkedAccountConfigurationId": "4ae16cc5-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"name": "Karan Kaushik",
"email": "emailHere",
"recipientId": "2",
"routingOrder": "2",
"excludedDocuments":[2]
}
The linkedAccountConfigurationId
parameter here (obtained from the network creator previously, as linkConfigurationId
) indicates that this envelope is a joint agreement and that this carbon copy recipient is the designated recipient on the network creator’s side.
The Joint Agreements sender can then also specify which documents to share with the network creator, by using the document visibility parameter excludedDocuments
. The documents that are shared with the network creator are called joint agreements. To share documents in a different way, such as after uploading them after envelope creation, please follow the alternative steps below.
Finally, the Joint Agreements designated recipient must be placed last in the routing order in the envelope by setting a relatively high value for routingOrder
.
By defining the linkedAccountConfigurationId
attribute, the sender is required to adhere to the requirements defined in the referenced Joint Agreements network configuration. In this example I have to require all recipients who are signing or viewing the joint agreement to go through recipient authentication via phone or SMS.
An alternative way to send a Joint Agreements envelope is to create a draft envelope, and then add the documents and recipients, including the Joint Agreements designated recipient, to the envelope after the fact. If you are creating your envelope this way, the way you would share documents with the network creator is done a bit differently. Instead of using the excludedDocuments document visibility parameter, you make a call to the updateRecipientsDocumentVisibility
API endpoint (Step 4 below).
Call EnvelopeLocks: create to obtain an edit lock on the envelope.
Call EnvelopeDocuments: updateList to add documents to the draft envelope. Any documents added to the envelope this way will be automatically available, or shared with, the Joint Agreements carbon copy designated recipient. Any documents not intended to be shared with the designated recipient will need to be excluded via the subsequent
updateRecipientsDocumentVisibility
API call (Step 4 in this list).Call EnvelopeRecipients: create to create the recipients, including the Joint Agreements carbon copy designated recipient, adhering to all the rules mentioned above.
Call EnvelopeDocumentVisibility: updateRecipientsDocumentVisibility to update the document visibility settings for the Joint Agreements carbon copy recipient created in Step 3 as needed. Sample payload body:
{ "documentVisibility": [ { "recipientId": "2", "documentId": "2", "visible": "false", "rights": "editable" } ] }
Call EnvelopeLocks: delete to delete the edit lock on the envelope.
You can also use our composite template model to create a Joint Agreement. However, care must be taken to reference the proper documentId and recipientId values when sharing documents with the Joint Agreements designated recipient. This is because with the composite template model, these IDs may change from what is specified in the create
call.
As an example, we recommend the following set of API calls if using the composite templates model:
Call Envelopes: create to create an Envelope as a draft.
{ "status": "created", "name": "Joint Agreement Test", "emailSubject": "Please Docusign this", "compositeTemplates": [ { "inlineTemplates": [ { "sequence": "10", "envelope": { "recipients": { "carbonCopies": [ { "linkedAccountConfigurationId": "", "name": "Joint Agreement Recipient", "email": "", "recipientId": "2", "routingOrder": "2" } ], "signers": [ { "roleName": "Agreement Signer", "recipientId": "1", "routingOrder": "1", "defaultRecipient": "true", "name": "Agreement Signer", "email": "", "identityVerification": { "inputOptions": [ { "name": "phone_number_list", "phoneNumberList": [ { "countryCode": "61", "number": "04123456789" } ], "valueType": "PhoneNumberList" } ], "steps": null, "workflowId": "Workflow ID from your account" }, "tabs": { "signHereTabs": [ { "name": "SignHere", "tabLabel": "SignHere", "documentId": "1", "pageNumber": "1", "xPosition": "75", "yPosition": "150" } ], "dateSignedTabs": [ { "name": "DateSigned", "tabLabel": "DateSigned", "documentId": "1", "pageNumber": "1", "xPosition": "72", "yPosition": "200" } ] } } ] } } } ], "document": { "documentId": "2", "name": "Visible to Joint Agreement Recipient", "fileExtension": "pdf", "documentBase64": "" } }, { "inlineTemplates": [ { "sequence": "20", "envelope": { "recipients": { "signers": [ { "roleName": "Agreement Signer", "recipientId": "1", "routingOrder": "1", "defaultRecipient": "true", "name": "Agreement Signer", "email": "", "identityVerification": { "inputOptions": [ { "name": "phone_number_list", "phoneNumberList": [ { "countryCode": "61", "number": "04123456789" } ], "valueType": "PhoneNumberList" } ], "steps": null, "workflowId": "Workflow ID from your account" }, "tabs": { "initialHereTabs": [ { "name": "InitialHere", "tabLabel": "InitialHere", "documentId": "2", "pageNumber": "1", "xPosition": "75", "yPosition": "150" } ], "dateSignedTabs": [ { "name": "DateSigned", "tabLabel": "DateSigned", "documentId": "2", "pageNumber": "1", "xPosition": "72", "yPosition": "200" } ] } } ] } } } ], "document": { "documentId": "1", "name": "Not Visible to Joint Agreement Signer", "fileExtension": "docx", "documentBase64": "" } } ] }
Call EnvelopeRecipients: List to return a list of the recipients on the envelope to get the
recipientId
of the Joint Agreements carbon copy designated recipient.Call EnvelopeDocuments: List to return a list of the documents on the envelope to get the
documentId
of the document in the envelope that you want to share with or hide from the Joint Agreements designated recipient.Call EnvelopeDocumentVisibility: updateRecipientsDocumentVisibility to update the document visibility settings for the Joint Agreements designated recipient, providing their
recipientId
as well as thedocumentId
obtained in Steps 2 and 3 and the appropriate value for thevisible
attribute,true
orfalse
. Please see the sample payload body above for this call.
Other situations
If your network creator (Custodian) is restricting PDF form field conversion to “Prefill and Recipient”, please keep the following in mind:
The shared joint agreement that you upload to the envelope cannot be a flattened PDF document with no Adobe form fields. It must retain any Adobe form fields and convert them to Docusign tabs, assigning the converted tabs to either one or more recipients in the envelope, or assigning them to prefill fields.
To convert an uploaded document’s form fields to Docusign prefill fields via API, you need to make a PUT call to EnvelopeDocuments: updateList, specifying the uploaded document.
Here’s a sample payload body for this call:
{
"documents": [
{
"documentId": "5",
"containsPdfFormFields": "true",
"transformPdfFields": true,
"pdfFormFieldOption": "MergeFormFieldsToPrefill"
}
]
}
Note: Assigning Adobe PDF form fields to prefill using the above API call will only work for documents uploaded to a draft envelope after the envelope has been created. It will not work for documents explicitly defined in the initial envelope create call.
Common errors
If Network-mandated recipient authentication requirements are not met for one or more recipients
{ "errorCode": "RECIPIENT_AUTHENTICATION_REQUIREMENTS_NOT_FULFILLED", "message": "There are recipient authentication requirements which have not been fulfilled. The following recipients and linked account requirements are at issue:\r\n\r\n{\"recipientsAtIssue\": [{\"name\":\"Bob Example\",\"selectedAuthTypes\":\"None\"}],\"linkedAccounts\":[{\"linkId\": \"9e8eea5a-xxx-xxxx-xxxx-xxxxxxxxx\",\"name\":\"Docusign Joint Agreements Test Account\",\"requiresAnyOfTheseAuthTypes\":\"SMS/Phone\"}],\"mutuallyAcceptableAuthTypes\": \"SMS/Phone\"}" }
The error message will note which recipients do not meet the requirements, and which recipient authentication types are allowed by the network configuration. Note: Starting in May 2024, Joint Agreements will make it possible to exclude from the network-mandated recipient authentication requirements those recipients who are signing or viewing only their own proprietary documents. These are the requirements:
The Joint Agreements network partner account (sender) has to have the Document Visibility feature turned on and set to one of the “Sender can set…” options. For more information document visibility settings, see our blog post, From the Trenches: Deep dive into document visibility.
The recipient to be excluded from recipient authentication cannot have any signer tabs assigned on the shared Joint Agreement document, or have access to the shared Joint Agreement document via the document visibility grid matrix.
The envelope API create call will need to set the enforceSignerVisibility API attribute to true.
2. If the linkedAccountConfigurationId value is not correct:
{
"errorCode": "UNSPECIFIED_ERROR",
"message": "Object reference not set to an instance of an object."
}
We recommend testing your Joint Agreements flow in your developer account first before moving to production.
Additional resources
Karan Kaushik began his Docusign career in January 2022. As a front-line developer support engineer, Karan enjoys working on complex technical problems. He is passionate about using technology to make people's day-to-day lives easier and simpler, leveraging his array of experience across information technology, cloud operations, and software development.