The Mercury Webhooks API — registering endpoints, and verifying inbound webhook delivery signatures.
Summary
Functions
Registers a new webhook endpoint. attrs accepts snake_case keys, e.g.
Deletes a webhook endpoint. DELETE /webhooks/{id}
Returns a single webhook by ID. GET /webhooks/{id}
Returns one page of webhooks. GET /webhooks
A lazy, auto-paginating stream of every webhook.
Updates a webhook. Setting status: :active reactivates a disabled
webhook. PUT /webhooks/{id}
Sends a test event to the webhook endpoint. POST /webhooks/{id}/verify
Verifies the signature on an inbound webhook delivery using constant-time HMAC-SHA256 comparison.
Functions
@spec create(client :: Mercury.Client.t(), attrs :: map() | keyword()) :: {:ok, Mercury.Webhook.t()} | {:error, Exception.t()}
Registers a new webhook endpoint. attrs accepts snake_case keys, e.g.:
Mercury.Webhooks.create(client, %{
url: "https://example.com/webhooks/mercury",
event_types: ["transaction.created", "transaction.updated"]
})POST /webhooks
@spec create!(client :: Mercury.Client.t(), attrs :: map() | keyword()) :: Mercury.Webhook.t()
@spec delete(client :: Mercury.Client.t(), webhook_id :: String.t()) :: :ok | {:error, Exception.t()}
Deletes a webhook endpoint. DELETE /webhooks/{id}
@spec delete!(client :: Mercury.Client.t(), webhook_id :: String.t()) :: :ok
@spec get(client :: Mercury.Client.t(), webhook_id :: String.t()) :: {:ok, Mercury.Webhook.t()} | {:error, Exception.t()}
Returns a single webhook by ID. GET /webhooks/{id}
@spec get!(client :: Mercury.Client.t(), webhook_id :: String.t()) :: Mercury.Webhook.t()
@spec list(client :: Mercury.Client.t(), opts :: keyword()) :: {:ok, Mercury.Page.t(Mercury.Webhook.t())} | {:error, Exception.t()}
Returns one page of webhooks. GET /webhooks
Accepts an :event_type filter in addition to the common list options.
@spec list!(client :: Mercury.Client.t(), opts :: keyword()) :: Mercury.Page.t(Mercury.Webhook.t())
@spec stream(client :: Mercury.Client.t(), opts :: keyword()) :: Enumerable.t()
A lazy, auto-paginating stream of every webhook.
@spec update( client :: Mercury.Client.t(), webhook_id :: String.t(), attrs :: map() | keyword() ) :: {:ok, Mercury.Webhook.t()} | {:error, Exception.t()}
Updates a webhook. Setting status: :active reactivates a disabled
webhook. PUT /webhooks/{id}
@spec update!( client :: Mercury.Client.t(), webhook_id :: String.t(), attrs :: map() | keyword() ) :: Mercury.Webhook.t()
@spec verify( client :: Mercury.Client.t(), webhook_id :: String.t(), attrs :: map() | keyword() ) :: :ok | {:error, Exception.t()}
Sends a test event to the webhook endpoint. POST /webhooks/{id}/verify
@spec verify!( client :: Mercury.Client.t(), webhook_id :: String.t(), attrs :: map() | keyword() ) :: :ok
@spec verify_signature( raw_body :: binary(), signature :: String.t(), signing_secret :: String.t() ) :: boolean()
Verifies the signature on an inbound webhook delivery using constant-time HMAC-SHA256 comparison.
Confirm the signing scheme first
The reference Go SDK does not implement inbound signature
verification, so this assumes the common convention of a
hex-encoded HMAC-SHA256(raw_request_body, signing_secret) digest
sent in a header. Confirm the exact header name and encoding
against the current Mercury webhooks
documentation for
your endpoint before relying on this in production — providers
sometimes use a composite header (e.g. t=<timestamp>,v1=<digest>)
instead of a bare digest, in which case extract the digest yourself
and pass it as signature.
raw_body must be the raw, unparsed request body bytes — signatures
will not match against a re-encoded/re-serialized payload.
Examples
Mercury.Webhooks.verify_signature(raw_body, signature_header, signing_secret)
#=> true | false