Verifies and parses incoming Moneyhub webhook deliveries.
Moneyhub can deliver webhooks as plain JSON or as a signed JWT (a
"Security Event Token" style payload) - which one you receive depends on
how the webhook endpoint was configured in the admin portal. parse/2
handles both transparently: given the raw request body (as a string) and
your MoneyHub.Config, it detects which shape was sent, verifies the
signature if present, and returns a MoneyHub.Webhooks.Event.
Moneyhub's webhook delivery has a 5 second response timeout and
performs at most one retry - your endpoint must acknowledge quickly
(return 200 immediately, do slow processing afterwards) or events will
be lost.
Example (Plug-based webhook endpoint)
def handle_webhook(conn, _params) do
{:ok, raw_body, conn} = Plug.Conn.read_body(conn)
case MoneyHub.Webhooks.parse(raw_body, config) do
{:ok, %MoneyHub.Webhooks.Event{id: "newTransactions"} = event} ->
MyApp.Jobs.enqueue(:sync_transactions, event.payload)
Plug.Conn.send_resp(conn, 200, "")
{:ok, %MoneyHub.Webhooks.Event{} = event} ->
MyApp.Jobs.enqueue(:handle_webhook, event)
Plug.Conn.send_resp(conn, 200, "")
{:error, _reason} ->
Plug.Conn.send_resp(conn, 400, "")
end
end
Summary
Functions
Parses and verifies a raw webhook request body, returning a
MoneyHub.Webhooks.Event struct.
Functions
@spec parse(String.t(), MoneyHub.Config.t()) :: {:ok, MoneyHub.Webhooks.Event.t()} | {:error, MoneyHub.Error.t()}
Parses and verifies a raw webhook request body, returning a
MoneyHub.Webhooks.Event struct.
Detects whether raw_body is a plain JSON object or a compact JWS
(three base64url segments separated by .) and verifies accordingly.
Plain JSON deliveries have no signature to check at the payload level
(verify transport security / a shared secret header instead, if your
webhook configuration uses one); JWT deliveries are verified against
Moneyhub's published JWKS exactly like an id_token.