View Source DocuSign.WebhookPlug (DocuSign v1.2.0)

Helper Plug to process webhook events and send them to a custom handler.

Based on the excellent Stripe webhook plug: https://github.com/beam-community/stripity-stripe/blob/v3.1.1/lib/stripe/webhook_plug.ex

Installation

To handle webhook events, you must first configure your application's endpoint. Add the following to endpoint.ex, before Plug.Parsers is loaded.

plug DocuSign.WebhookPlug,
  at: "/webhook/docusign",
  handler: MyAppWeb.DocuSign.WebhookHandler,
  hmac_secret_key: fn -> Application.get_env(:myapp, :hmac_secret_key) end

If you have not yet added a webhook to your DocuSign account, you can do so by visiting the 'Settings > Connect'. Use the route you configured in the endpoint above and copy the HMAC secret key into your app's configuration.

Supported options

  • at: The URL path your application should listen for DocuSign webhooks on. Configure this to match whatever you set in the webhook.
  • handler: Custom event handler module that accepts map() payloads and processes them within your application. You must create this module.
  • secret: Webhook HMAC secret obtained from the DocuSign Connect dashboard. This can also be a function or a tuple for runtime configuration.

Handling events

You will need to create a custom event handler module to handle events.

Your event handler module should implement the DocuSign.Webhook.Handler behavior, defining a handle_webhook/1 function which takes a map() payload and returns either {:ok, term} or :ok. This will mark the event as successfully processed. Alternatively handler can signal an error by returning :error or {:error, reason} tuple, where reason is an atom or a string. HTTP status code 400 will be used for errors.

Refer to https://developers.docusign.com/platform/webhooks/connect/json-sim-event-reference/ for the possible payloads you may receive. Note that these payloads can vary based on your Connect configuration.

Example

# lib/myapp_web/docusign_handler.ex

defmodule MyAppWeb.DocuSignHandler do
  @behaviour DocuSign.Webhook.Handler

  @impl true
  def handle_webhook(%{"event" => "envelope-completed"} = event) do
    # TODO: handle the envelope-completed event
  end

  @impl true
  def handle_webhook(%{"event" => "envelope-discard"} = event) do
    # TODO: handle the "envelope-discard" event
  end

  # Return HTTP 200 for unhandled events
  @impl true
  def handle_webhook(_event), do: :ok
end

Configuration

You can configure the HMAC secret key in your app's own config file. For example:

config :myapp,
  # [...]
  hmac_secret_key: "AB123_******"

You may then include the secret in your endpoint:

plug DocuSign.WebhookPlug,
  at: "/webhook/docusign",
  handler: MyAppWeb.DocuSign.WebhookHandler,
  hmac_secret_key: Application.get_env(:myapp, :hmac_secret_key)

Runtime configuration

If you're loading config dynamically at runtime (eg with runtime.exs or an OTP app) you must pass a tuple or function as the secret.

# With a tuple
plug DocuSign.WebhookPlug,
  at: "/webhook/docusign",
  handler: MyAppWeb.DocuSign.WebhookHandler,
  secret: {Application, :get_env, [:myapp, :hmac_secret_key]}

# Or, with a function
plug DocuSign.WebhookPlug,
  at: "/webhook/docusign",
  handler: MyAppWeb.DocuSign.WebhookHandler,
  secret: fn -> Application.get_env(:myapp, :hmac_secret_key) end

HMAC secret key

Only 1 HMAC secret key can be configured. It is assumed that to rotate the HMAC secret key:

  1. An additional HMAC secret key is added to the DocuSign Connect configuration.
  2. The HMAC secret key of the plug is updated to this new secret key.
  3. Finally the previous HMAC secret key is removed from the DocuSign Connect.

HMAC signatures

DocuSign can send up to 100 HMAC signatures, which would happen if you have configured 100 HMAC secret keys in your Connect dashboard. Although this is unlikely, the plug will check all of the signatures provided.