Docusign API server templates local docs and tabs

2019-08-20 10:31发布

I'm working on a DocuSign integration. I have the basics functional but can't seem to figure out how to merge a local document (PDF) with a server template such that tabs configured on the server template get used or overlaid on the passed document.

My template is defined on the server and I can use it directly from the web UI without issue (it's a W4 form). The template has three tabs (SSN, Sign here, and date) as you can see below. Accessing this template via it's ID using the API Explorer yields the following json

{
    "envelopeTemplateDefinition": {
        "templateId": "_redacted_",
        "name": "W4 3/13/2017",
        "shared": "true",
        "password": "",
        "description": "",
        "lastModified": "2017-06-05T18:45:28.4470000Z",
        "lastModifiedBy": {
            "userName": "Andrew",
            "userId": "_redacted_",
            "email": "my_email_address",
            "uri": "/users/_redacted_
        },
        "pageCount": 2,
        "uri": "/templates/_redacted_",
        "folderName": "Templates",
        "folderId": "_redacted_",
        "folderUri": "/folders/_redacted_",
        "owner": {
            "userName": "Andrew",
            "userId": "_redacted_",
            "email": "my_email_address"
        }
    },
    "documents": [
        {
            "documentId": "46677269",
            "uri": "/envelopes/_redacted_/documents/46677269",
            "name": "W4.pdf",
            "order": "1",
            "pages": "2",
            "display": "inline",
            "includeInDownload": "true",
            "signerMustAcknowledge": "no_interaction",
            "templateLocked": "false",
            "templateRequired": "false",
            "documentGroup": "content"
        }
    ],
    "emailSubject": "Please DocuSign: W4.pdf",
    "emailBlurb": "",
    "signingLocation": "online",
    "autoNavigation": "true",
    "envelopeIdStamping": "true",
    "authoritativeCopy": "false",
    "notification": {
        "reminders": {
            "reminderEnabled": "false",
            "reminderDelay": "0",
            "reminderFrequency": "0"
        },
        "expirations": {
            "expireEnabled": "true",
            "expireAfter": "120",
            "expireWarn": "0"
        }
    },
    "enforceSignerVisibility": "false",
    "enableWetSign": "true",
    "allowMarkup": "false",
    "allowReassign": "true",
    "recipients": {
        "signers": [
            {
                "defaultRecipient": "false",
                "tabs": {
                    "signHereTabs": [
                        {
                            "stampType": "signature",
                            "name": "SignHere",
                            "tabLabel": "Signature _redacted_",
                            "scaleValue": 1.0,
                            "optional": "false",
                            "documentId": "46677269",
                            "recipientId": "94043042",
                            "pageNumber": "1",
                            "xPosition": "193",
                            "yPosition": "682",
                            "tabId": "_redacted_",
                            "templateLocked": "false",
                            "templateRequired": "false"
                        }
                    ],
                    "dateSignedTabs": [
                        {
                            "name": "DateSigned",
                            "value": "",
                            "tabLabel": "Date Signed _redacted_",
                            "font": "lucidaconsole",
                            "fontColor": "black",
                            "fontSize": "size9",
                            "documentId": "46677269",
                            "recipientId": "94043042",
                            "pageNumber": "1",
                            "xPosition": "480",
                            "yPosition": "713",
                            "tabId": "_redacted_",
                            "templateLocked": "false",
                            "templateRequired": "false"
                        }
                    ],
                    "ssnTabs": [
                        {
                            "validationPattern": "",
                            "validationMessage": "",
                            "shared": "false",
                            "requireInitialOnSharedChange": "false",
                            "requireAll": "false",
                            "value": "",
                            "width": 144,
                            "required": "true",
                            "locked": "false",
                            "concealValueOnDocument": "true",
                            "disableAutoSize": "false",
                            "maxLength": 4000,
                            "tabLabel": "Text _redacted_",
                            "font": "lucidaconsole",
                            "fontColor": "black",
                            "fontSize": "size9",
                            "documentId": "46677269",
                            "recipientId": "94043042",
                            "pageNumber": "1",
                            "xPosition": "442",
                            "yPosition": "563",
                            "tabId": "_redacted_",
                            "templateLocked": "false",
                            "templateRequired": "false"
                        }
                    ]
                },
                "signInEachLocation": "false",
                "name": "",
                "email": "",
                "recipientId": "94043042",
                "accessCode": "",
                "requireIdLookup": "false",
                "routingOrder": "1",
                "note": "",
                "roleName": "New Employee",
                "deliveryMethod": "email",
                "templateLocked": "false",
                "templateRequired": "false",
                "inheritEmailNotificationConfiguration": "false"
            }
        ],
        "agents": [ ],
        "editors": [ ],
        "intermediaries": [ ],
        "carbonCopies": [ ],
        "certifiedDeliveries": [ ],
        "inPersonSigners": [ ],
        "recipientCount": "1"
    }
}

What I want to do is apply this template to a PDF that's already partially filled out such that when the signer get's it the tabs defined in the server template are used for the sining.

As it stands now, there's nothing. Just the partially filled out PDF I passed in below as base64 data, with none of the server template tabs to fill out or sign. Here's my json for the API call (in PHP).

  $data = array (
        "emailBlurb" => "Test Email Body",
        "emailSubject" => "Test Email Subject",
        "status" => "sent",
        "compositeTemplates" => array(array(
            "document" => array(
                "documentId" => 46677269,
                "name" => $documentName,
                "documentBase64" => $document
            ),
            "serverTemplates" => array(array(

                "sequence" => 1,
                "templateId" => "_redacted_"
            )),
            "inlineTemplates" => array(array(
                "sequence" => 2,
                "recipients" => array(
                    "signers" => array(array(
                        "email" => $recipientEmail,
                        "name" => $recipientName,
                        "recipientId" => $recipientID,
                        "roleName" => "New Employee"
                    ))
                )
            ))
        ))
  ); //$data = array...

I suspect that I'm simply missing some appropriate reference to the tabs defined in the server template. But documentation is atrocious and I've already spent several hours combing the web. Any help would be much appreciated.

UPDATE1

As requested, here's the code that generates the envelope successfully:

function c_requestSignature($templateID, $recipientName, $recipientEmail, $recipientID, $document){
  //function sets up the passed document for signing using the specified template
  $documentName = "W4"; //FIXME fetch document name using templateID
  $baseURL = c_docusignBaseURL();
  $accountId = c_docusignAccountId();
  $header = c_docusignHeader();
  $data = array (
        "emailSubject" => "Please sign " . $documentName,
        //"emailBlurb" => "Test Email Body",
        "status" => "sent",
        "compositeTemplates" => array(
            "compositeTemplate" => array(
                "serverTemplates" => array(
                    "serverTemplate" => array(
                        "sequence" => "1",
                        "templateId" => "_redacted_"
                    )
                ),
                "inlineTemplates" => array(
                    "inlineTemplate" => array(
                        "sequence" => "2",
                        "recipients" => array(
                            "signers" => array(
                                "signer" => array(
                                    "name" => $recipientName,
                                    "email" => $recipientEmail,
                                    "roleName" => "NewHire"
                                )
                            )
                        )
                    )
                ),
                "document" => array(
                    "documentId" => "1",
                    "name" => $documentName,
                    "fileExtension" => "pdf",
                    "documentBase64" => $document
                )
            )
        )
  );

  // Send to the /envelopes end point, which is relative to the baseUrl received above.
  $curl = curl_init($baseURL . "/envelopes" );
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
  curl_setopt($curl, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string),
    "X-DocuSign-Authentication: $header" )
  );

  $json_response = curl_exec($curl); // Do it!

  $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  if ( $status != 201 ) {
    echo "Error calling DocuSign, status is:" . $status . "\nerror text: ";
    print_r($json_response); echo "\n";
    exit(-1);
  }

  $response = json_decode($json_response, true);
  $envelopeId = $response["envelopeId"];

  error_log ("successfully created envelope: $envelopeId");
  $url = getSignatureURL($envelopeId, $recipientName, $recipientEmail, $recipientID);
  return $url;
}//c_requestSignature()...

The function getSignatureURL() has code as follows:

function getSignatureURL($envelopeId, $recipientName, $recipientEmail, $recipientID){
  //function retrieves the signing ceremony UX URL from DocuSign
  $baseURL = c_docusignBaseURL();
  $accountId = c_docusignAccountId();
  $header = c_docusignHeader();
  //set up the data we'll send to the Docusign server
  $data = array("returnUrl" => "http://_redacted_",
    "authenticationMethod" => "none",
    "email" => $recipientEmail,
    "name" => $recipientName,
    "recipientId" => $recipientID,
    //"recipientId" => "1",
    //"clientUserId" => $recipientID,
    "userName" => $recipientName
  );
  $data_string = json_encode($data);
  //set up curl
  $curl = curl_init($baseURL . "/envelopes/$envelopeId/views/recipient" );
  curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($curl, CURLOPT_POST, true);
  curl_setopt($curl, CURLOPT_POSTFIELDS, $data_string);
  curl_setopt($curl, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'Content-Length: ' . strlen($data_string),
    "X-DocuSign-Authentication: $header" )
  );
  //make the API call
  $json_response = curl_exec($curl);
  $status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
  if ( $status != 201 ) {
    echo "error calling webservice, status is:" . $status . "\nerror text is --> ";
    print_r($json_response); echo "\n";
    exit(-1);
  }
  //retrieve and process the response
  $response = json_decode($json_response, true);
  return $response["url"];
}

UPDATE 2

Here's the raw json as requested...

{
  "emailSubject": "some subject",
  "status": "sent",
  "compositeTemplates": [
    {
      "serverTemplates": [
        {
          "sequence": "1",
          "templateId": "_redacted_"
        }
      ],
      "inlineTemplates": [
        {
          "sequence": "2",
          "recipients": {
            "signers": [
              {
                "name": "Andrew Tester1",
                "email": "my_email_address",
                "roleName": "NewHire",
                "recipientId": "1234",
                "clientUserId": "1234"
              }
            ]
          }
        }
      ],
      "document": {
        "documentId": "1",
        "name": "W4",
        "fileExtension": "pdf",
        "documentBase64": "_redacted_"
      }
    }
  ]
}

Update 3

I had a problem which was preventing me from seeing the proper output of the above json. With that fixed, now I'm getting the following error:

Error calling DocuSign, status is:400 error text: { "errorCode": "TAB_REFERS_TO_MISSING_DOCUMENT", "message": "The DocumentId specified in the tab element does not refer to a document in this envelope. Tab refers to DocumentId 46677269 which is not present." }

If I change the document stanza above as follows:

      "document": {
        "documentId": "46677269",
        "name": "W4",
        "fileExtension": "pdf",
        "documentBase64": "_redacted_"
      }

The error goes away, but I still get a signing ceremony with no tabs.

2条回答
Emotional °昔
2楼-- · 2019-08-20 11:10

Well this was a thorny problem, but I found the solution (finally), with some help form the folk at Docusign. I thought I'd post it here for those who might run into this in the future.

Solution The json structure passed to the DocuSign API is extremely important. If there are any errors in it at all, it won't work right, and the error message is not always helpful. Furthermore, in what I was doing, the specific parameters passed were also crucial. The envelope generation code above is correct, though with the caveat that you must specify the PDF document ID that is part of the template stored on DocuSign's servers. You can query this via their API given the envelope ID (which is what I'm doing). Apparently this didn't use to be required, but now it is and there's no documentation anywhere stating that.

My fundamental problem with the signature tabs though, was the code requesting the signing ceremony URL. I had extra parameters which were being accepted without error, but were messing things up. Discovered this, by using DocuSign's REST API explorer to generate a working signing ceremony URL (complete with all the proper signature tabs), and comparing the output json whith what I was trying to pass in my code.

Here's the working PHP code that generates the correct json:

  $data = array(
    "authenticationMethod" => "email",
    "clientUserId" => $recipientID,
    "email" => $recipientEmail,
    "returnUrl" => "_redacted_", 
    "userName" => $recipientName
  );
  $data_string = json_encode($data);
查看更多
Lonely孤独者°
3楼-- · 2019-08-20 11:33

The following request can be used to create an envelope from the Server Template. The server templates document will be replaced with the new document that is specified in the request.

{
    "emailSubject": "Test Email Subject",
    "emailBlurb" :  "Test Email Body",
    "status": "sent",
    "compositeTemplates": [
        {
            "serverTemplates": [
                {
                    "sequence": "1",
                    "templateId": "86841739-f12d-460e-9807-23a9b90cff6b"
                }
            ],
            "inlineTemplates": [
                {
                    "sequence": "1",
                    "recipients": {
                        "signers": [
                            {
                                "name": "Jane Doe",
                                "email": "janedoe@acme.com",
                                "roleName": "New Employee"
                            }
                        ]
                    }
                }
            ],       
            "document": {
                "documentId": "1",
                "name": "Your Doc Name",
                "fileExtension": "pdf",
                "documentBase64": ""
            }
        }       
    ]
}
查看更多
登录 后发表回答