Last updated

Webhooks

When your app needs information about specific events that have occurred, it can subscribe to NVSEP webhook topics as a mechanism for receiving near-real-time data about these events.

Webhooks are useful for keeping your app in sync with NVSEP data, or as a trigger to perform an additional action after that event has occurred. They are also a performant alternative to continuously polling for changes.

Webhooks can be configured through the NVSEP Portal. The following webhook subscription topics are available:

Webhook Topics

Webhook TopicAPI NameTrigger
Self-Exclusion Createdcfs_exclusions.createdCalled when a new self-exclusion has been created.

Sample Payloads

Event: cfs_exclusions.created

{
  "id": "20c6d434-9f90-48e4-a246-993ffab00477",
  "type": "cfs_exclusions.created",
  "createdAt": "2023-01-01T12:00:01Z",
  "version": "1.0",
  "data": {
    "createdAt": "2023-01-01T12:00:00Z",
    "createdByOrg": {
      "id": "473bd688-ad6b-42dc-bbe8-8342537483cc",
      "name": "IdPair, Inc."
    },
    "endDate": "2023-12-31",
    "id": "44cd42ee-1982-423a-9b76-e629f952df88",
    "player": {
      "hashes": [
        {
          "createdAt": "2024-01-01T10:00:00Z",
          "hash1": "hash_value_1",
          "hash2": "hash_value_2",
          "hash3": "hash_value_3"
        }
      ]
    },
    "startDate": "2023-01-01"
  }
}

Verifying Authenticity

You are strongly encouraged to validate the incoming webhook payload through an HMAC signature verification process. This can provide assurance that the request comes from NVSEP.

  1. Extract the x-nvsep-hmac-sha256 header from the incoming request.
  2. Use your Webhook Signing Key to compute an HMAC digest of the request body.
  3. Compare the computed HMAC digest to the x-nvsep-hmac-256 header securely.

Sample pseudocode:

defmodule NVSEPWebhook do
  @moduledoc """
  Validates NVSEP webhook HMAC signature.
  """

  @doc """
  Validates the NVSEP HMAC signature.

  ## Parameters
    - headers: Map of HTTP headers from the webhook request.
    - body: Raw body of the webhook request.

  ## Returns
    - `:ok` if the HMAC is valid.
    - `:error` if the HMAC is invalid.
  """
  def validate_hmac(headers, body) do
    with signing_key <- System.get_env("NVSEP_WEBHOOK_SIGNING_KEY"),
         {:ok, hmac_header} <- get_hmac_header(headers),
         computed_hmac <- compute_hmac(body, signing_key),
         true <- secure_compare(hmac_header, computed_hmac) do
      :ok
    else
      _ -> :error
    end
  end

  defp get_hmac_header(headers) do
    case Map.get(headers, "x-nvsep-hmac-sha256") do
      nil -> {:error, :missing_hmac_header}
      hmac -> {:ok, hmac}
    end
  end

  defp compute_hmac(body, signing_key) do
    :crypto.mac(:hmac, :sha256, signing_key, body)
    |> Base.encode64()
  end

  defp secure_compare(a, b) when is_binary(a) and is_binary(b) do
    Plug.Crypto.secure_compare(a, b)
  end

  defp secure_compare(_, _), do: false
end

Troubleshooting

You should monitor for and respond to failed webhook delivery notifications. A webhook will be retried up to 8 times, after multiple failures in a 24 hour period the webhook subscription will be removed.