MoneyHub.Webhooks (MoneyHub v1.0.0)

Copy Markdown View Source

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

parse(raw_body, config)

@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.