0

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.

Andrew
  • 421
  • 2
  • 12

2 Answers2

0

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": ""
            }
        }       
    ]
}
Praveen Reddy
  • 7,295
  • 2
  • 21
  • 43
  • Does this preserve the tags present in the server template? (i.e. the places to sign?). That's my fundamental problem. I need the tags on the server template to persist and be applied to the passed in document. I'll try this out later tonight and post results. – Andrew Jun 06 '17 at 00:20
  • Yes it should preserve the Tabs, unless the new document has fewer pages than the original document and tabs were present in the truncated pages. – Praveen Reddy Jun 06 '17 at 01:04
  • I'm sad to report that the above example doesn't seem to work. Implemented it exactly as above. The resulting PDF has no tabs in it whatsoever. – Andrew Jun 06 '17 at 22:51
  • Can you please show us your code. Can you also let me know the envelopeId that was created. – Praveen Reddy Jun 06 '17 at 22:55
  • Question updated to include the PHP code I'm working with. – Andrew Jun 06 '17 at 23:29
  • I looked at the last 5 envelopes that you have created. 3 of them have Tabs and 2 of them don't have tabs. Also it seems like you have changed the Role Name in the template from 'New Employee' to 'New HIre'. Are you sure you are passing the correct roleName in your request? – Praveen Reddy Jun 06 '17 at 23:45
  • Yes the change was just an attempt to see if the space in the roleName was making a difference or not. So that was arbitrary. I changed to code to match. – Andrew Jun 06 '17 at 23:54
  • As to the various envelopes created. whether or not they have tabs, I don't know. I'm measuring success, by what I see on the screen from clicking the signing ceremony UX link. What I'm expecting is a signing session showing the tabs configured in the server template. – Andrew Jun 06 '17 at 23:56
  • With the present information you have provided, I cannot tell where the problem is. Can you please post the raw JSON request that you are sending to create the envelope. – Praveen Reddy Jun 07 '17 at 01:00
  • Updated question with raw json as requested. Basically dumped the variable. I edited slightly to scrub email addresses and removed the base64 data. – Andrew Jun 07 '17 at 01:41
  • Updated again to include an error message. Maybe we're getting somewhere? – Andrew Jun 07 '17 at 01:53
  • I think I know what is going on. Your tab positions are a bit large. `(402, 1420) (1000, 1485) (920, 1172)` They are probably being placed outside the page. Thats the reason you are unable to see them. Try placing the tabs on the template at the start of the document. The other option is to make sure the new document is of the same resolution as that of old document. Also open the template in the DOcusign Web UI and make sure you are able to see the tabs on the document. – Praveen Reddy Jun 07 '17 at 02:02
  • I am able to see the tabs in the DocuSign UI. I'm not sure I follow what you mean by the tab positions being large. They were graphically placed on the pdf in the UI where the signature needs to be when the template was created. I suppose I could programmatically create new tabs and maintain definitions for them avoiding templates alltogether. But that's a significant departure from the workflow we had envisioned. Our thought is to allow admin users to manage the templates in the UI, and then just use them by their ID's. Could you explain further what you mean? – Andrew Jun 07 '17 at 04:14
  • The tabs are definitely there on the envelope. You are not seeing them as they are probably outside the page dimensions. To tell your exact problem I will have to look at the document you are using in your template and document you are supplying in the envelope creation request. Is it possible to share them – Praveen Reddy Jun 07 '17 at 04:19
  • Updated your answer with links to the files as suggested. Links will be available for 7 days. For the server document I just exported the template from my docusign account (json file) – Andrew Jun 07 '17 at 18:46
0

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);
Andrew
  • 421
  • 2
  • 12