Connect webhooks with JSON notifications

Connect webhooks with JSON notifications are available now for developer demo accounts and are being rolled out in production, too. This blog post has all the details.

What is a webhook?

With most APIs, including the DocuSign eSignature REST API, client applications initiate network calls to the API platform. But determining the status of an object in the platform is tricky, because the only way to do so using regular API calls is to poll the API platform, asking and re-asking about the status of an object such as an envelope. Polling is an inefficient use of both client and platform resources and is limited by many systems, including DocuSign.

In contrast, with webhooks, the developer either administratively or programmatically registers a webhook subscription, including the URL of the developer’s application. Then, when the status of the platform object changes, the platform proactively calls the developer’s application with a notification message that includes the details of the update.

DocuSign offers account-wide webhooks via Connect Custom configurations (subscriptions) and envelope-specific webhooks via the Envelopes:create eventNotification attribute.

See the Connect developer documentation for more information.

Webhooks behind the firewall

Traditionally, webhooks have required customers’ application servers to be accessible from the public internet to enable the incoming notifications from the platform. This often requires opening the corporate firewall. 

DocuSign also supports the use of a platform as a service vendor (such as AWS, Azure, or others) as an intermediate queuing system. This enables your application to receive the webhook notifications rapidly, with no changes to your corporate firewall. And the cost is usually free or a few dollars a month. This blog post has the details and example code.

Administratively configuring JSON notifications

Use the eSignature Administration app’s Connect panel to create a new custom configuration. The form now includes a Data Format setting, which can be used to select the REST v2.1 (JSON) format. 

Just as with the XML format, different sets of data can be included with the JSON notifications. See the screenshot below for the available options.

Data format options for Connect notifications

JSON notifications restrictions and recommendations

  • JSON notification messages are only available if the account is set to use the aggregate style of notification queuing.
  • A maximum of 10 account-level Connect configurations (subscriptions) can use the JSON payload format.
  • There is no limit on the number of envelopes with event notifications that use the JSON payload format.
  • Similar to XML webhook notifications, we do not recommend that you configure the webhook notifications to include either Documents or Attachments, since that data will cause very large notification payloads. Instead, use the eSignature REST API to download documents and attachments as needed.
  • Once a webhook configuration has been created, its data format can not be changed.

Per-envelope webhooks

Per-envelope webhooks are enabled by including the eventNotification attribute with the Envelope object.

The eventNotification object now includes a new attribute, eventData. The attribute is set to an object with three attributes: {version, format, and includeData}: 

Attribute Values Description
version "restv2.1" | "legacy" Default is "legacy"
format "json" | "xml" If version is "legacy" (or not included) then default is "xml". If version is "restv2.1" then default is "json".
includeData Array of strings. Valid items: "custom_fields", "extensions", "folders", "recipients", "powerform", "tabs", "payment_tabs", "documents", "attachments" Optional: additional sets of data that can be included with the JSON payload. "extensions": include the email settings for the envelope

Migrating from XML notifications

The Sender’s account ID

The sender’s account ID is now included in the guid format within the sender attribute:

"sender": {
   "userName": "Larry Kluger",
   "userId": "7b3d1245-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "accountId": "7a9312b8-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
   "email": "larry@example.com"
},

If you need the short-form version of the account ID, it is available via the Accounts:get API method. See the externalAccountId response attribute.

Envelope Void reason

When it’s available, the envelope void reason is included by default:

"voidedDateTime": "2021-01-27T11:39:39.557Z",
"voidedReason": "This is the void reason.",

documentFields data

The documentFields metadata attributes of document objects are not available with JSON notification messages. Use the EnvelopeDocumentFields:list API method to obtain the data.

Time zone information

JSON payloads include time zone information with their datetime data. Therefore, the time zone information available for XML notifications is no longer needed and is planned to be removed from future JSON format notification options.

TimeGenerated attribute

The TimeGenerated attribute is obsolete. It is currently included in the JSON notification, but will be removed in the March or April 2021 release. 

Known issues

For account-level JSON notifications, the administration tool includes settings for Envelope Voided reason, Sender Account, and Document Fields. 

Those three settings do not have any effect and will be removed from the administration tool in the future. To discuss any problems this causes with Customer support, reference internal ticket MAR-35665. 

Example per-envelope webhook request

{
    "emailSubject": "Please sign the attached document",
    "status": "sent",
    "eventNotification": {
        "url": "https://apps.example.com/app2/webhook-listener",
        "requireAcknowledgment": "true",
        "loggingEnabled": "true",
        "envelopeEvents": [
            {"envelopeEventStatusCode": "Sent",
            "includeDocuments": "false"},
            {"envelopeEventStatusCode": "Delivered",
            "includeDocuments": "false"},
            {"envelopeEventStatusCode": "Completed",
            "includeDocuments": "false"},
            {"envelopeEventStatusCode": "Declined",
            "includeDocuments": "false"},
            {"envelopeEventStatusCode": "Voided",
            "includeDocuments": "false"}
        ],
        "recipientEvents": [
            {"recipientEventStatusCode": "Sent",
            "includeDocuments": "false"},
            {"recipientEventStatusCode": "Delivered",
            "includeDocuments": "false"},
            {"recipientEventStatusCode": "Completed",
            "includeDocuments": "false"},
            {"recipientEventStatusCode": "Declined",
            "includeDocuments": "false"},
            {"recipientEventStatusCode": "AuthenticationFailed",
            "includeDocuments": "false"},
            {"recipientEventStatusCode": "AutoResponded",
            "includeDocuments": "false"}
        ],
        "eventData": {
            "version": "restv2.1",
            "format":  "json",
            "includeData": ["custom_fields", "extensions", "folders",
            	"recipients", "powerform", "tabs", "payment_tabs"]
        }
    },
    "recipients": {
      "signers": [
… 

Example JSON notification message

{
  "status": "sent",
  "documentsUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/documents",
  "recipientsUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/recipients",
  "attachmentsUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/attachments",
  "envelopeUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx",
  "emailSubject": "Please sign the attached documents",
  "envelopeId": "37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx",
  "signingLocation": "online",
  "customFieldsUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/custom_fields",
  "notificationUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/notification",
  "enableWetSign": "true",
  "allowMarkup": "false",
  "allowReassign": "true",
  "createdDateTime": "2021-01-27T19:28:04.513Z",
  "lastModifiedDateTime": "2021-01-27T19:28:04.53Z",
  "initialSentDateTime": "2021-01-27T19:28:06.077Z",
  "sentDateTime": "2021-01-27T19:28:06.077Z",
  "statusChangedDateTime": "2021-01-27T19:28:08.31Z",
  "documentsCombinedUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/documents/combined",
  "certificateUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/documents/certificate",
  "templatesUri": "/envelopes/37b137e7-d31b-xxxx-xxxx-xxxxxxxxxxxx/templates",
  "brandId": "c153d327-39da-xxxx-xxxx-xxxxxxxxxxxx",
  "expireEnabled": "true",
  "expireDateTime": "2021-05-27T19:28:06.077Z",
  "expireAfter": "120",
  "sender": {
    "userName": "Larry Kluger",
    "userId": "7b3d1245-0106-xxxx-xxxx-xxxxxxxxxxxx",
    "accountId": "7a9312b8-a9ba-xxxx-xxxx-xxxxxxxxxxxx",
    "email": "larry@example.com"
  },
  "folders": [
    {
      "name": "Sent Items",
      "type": "sentitems",
      "owner": {
        "userId": "7b3d1245-xxxx-xxxx-xxxxxxxxxxxx",
        "email": "larry@example.com"
      },
      "folderId": "314cfe84-e72b-xxxx-xxxx-xxxxxxxxxxxx",
      "uri": "/folders/314cfe84-e72b-xxxx-xxxx-xxxxxxxxxxxx"
    },
    {
      "name": "out_for_signature"
    }
  ],
  "customFields": {
    "textCustomFields": [
      {
        "fieldId": "1053591xxxx",
        "name": "Order ID",
        "show": "true",
        "required": "false",
        "value": "123456"
      }
    ],
    "listCustomFields": [
      {
        "listItems": [
          "Red",
          "Blue",
          "Gold"
        ],
        "fieldId": "1053591xxxx",
        "name": "Team",
        "show": "true",
        "required": "false",
        "value": "Red"
      }
    ]
  },
  "recipients": {
    "signers": [
      {
        "tabs": {
          "signHereTabs": [
            {
              "stampType": "signature",
              "name": "SignHere",
              "tabLabel": "Sign Here",
              "scaleValue": "1",
              "optional": "false",
              "documentId": "1",
              "recipientId": "1",
              "pageNumber": "1",
              "xPosition": "169",
              "yPosition": "482",
              "anchorString": "/sig1/",
              "anchorXOffset": "20",
              "anchorYOffset": "10",
              "anchorUnits": "pixels",
              "anchorCaseSensitive": "false",
              "anchorMatchWholeWord": "true",
              "anchorHorizontalAlignment": "left",
              "anchorTabProcessorVersion": "v1_3",
              "tabId": "cb8d1b1b-3130-xxxx-xxxx-xxxxxxxxxxxx",
              "tabType": "signhere"
            }
          ]
        },
        "creationReason": "sender",
        "isBulkRecipient": "false",
        "requireUploadSignature": "false",
        "name": "Signer's name",
        "firstName": "",
        "lastName": "",
        "email": "signer_email@example.com",
        "recipientId": "1",
        "recipientIdGuid": "ff3c9f37-7071-xxxx-xxxx-xxxxxxxxxxxx",
        "requireIdLookup": "false",
        "userId": "c0003340-4464-xxxx-xxxx-xxxxxxxxxxxx",
        "routingOrder": "1",
        "status": "autoresponded",
        "completedCount": "0",
        "deliveryMethod": "email",
        "totalTabCount": "1",
        "recipientType": "signer"
      }
    ],
    "agents": [],
    "editors": [],
    "intermediaries": [],
    "carbonCopies": [],
    "certifiedDeliveries": [],
    "inPersonSigners": [],
    "seals": [],
    "witnesses": [],
    "recipientCount": "1",
    "currentRoutingOrder": "1"
  },
  "purgeState": "unpurged",
  "envelopeIdStamping": "true",
  "is21CFRPart11": "false",
  "signerCanSignOnMobile": "true",
  "autoNavigation": "true",
  "isSignatureProviderEnvelope": "true",
  "hasFormDataChanged": "false",
  "allowComments": "true",
  "hasComments": "false",
  "allowViewHistory": "true",
  "disableResponsiveDocument": "false",
  "envelopeMetadata": {
    "allowAdvancedCorrect": "true",
    "enableSignWithNotary": "false",
    "allowCorrect": "true"
  },
  "anySigner": null,
  "envelopeLocation": "current_site",
  "isDynamicEnvelope": "false"
}

Summary

JSON notifications are now available for account-level and envelope-specific webhooks. The new feature makes it easier than ever to incorporate webhook status updates with your application instead of polling.

Additional resources

Larry Kluger
Author
Larry Kluger
Lead Developer Advocate
Published
Related Topics