Webhook Format

JSON

This is the default format. We will send the payload exactly as it appears in the other pages of this documentation, which is a JSON object with a Content-Type of application/json

Schema

JWT (JSON Web Token)

This format is based on JSON Web Tokens and provides a mechanism by which messages can be verified to ensure that only messages coming Moneyhub can be accepted by your system. These messages will be encoded like a JWT and delivered with a Content-Type of application/jwt

Given the Payment Completed webhook, the JWT encoded version look something like the following:

eyJraWQiOiJEOUpBTm1ZZlNHX2tidDJLUnBUS283UUNOSDJfUkstMGE3ODd5am0wN3p3IiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2lkZW50aXR5LWRldi5tb25leWh1Yi5jby51ayIsImF1ZCI6ImQ5ZGM5ZDVlLWQxOTAtNDM4Yy1iNjU4LWE0YmUzNzc5MTAwZCIsImp0aSI6ImM5ZDEzM2UwLWU3MDgtNDAyZC1hNmI3LWRjOGZmOWMyOWExYyIsInN1YiI6IjVmNzVhOWY5NDdmOWJkNzRkOTIxYTZjOSIsImV2ZW50cyI6eyJ1cm46Y29tOm1vbmV5aHViOmV2ZW50czpwYXltZW50LWNvbXBsZXRlZCI6eyJwYXltZW50SWQiOiJkYzk0NDZlZS1hZmMxLTRiNDctYmFiNS0yYjAxYzdkYTA5ZTMiLCJzdGF0dXMiOiJjb21wbGV0ZWQiLCJwYXltZW50U3VibWlzc2lvbklkIjoiMmJlOGNiZTUtZTEzOC00M2M1LWJjNTgtNzYwY2VmYTg5MjQ4Iiwic3VibWl0dGVkQXQiOiIyMDIwLTEwLTAxVDEwOjA1OjQ1LjM3NFoifX0sImlhdCI6MTYwMTU0Njc4MX0.Fld7AM3ywFUXaZYA8uFoGyiWalRhvM8V24a_n0pahYs8o2YGVk-5DCBVNwGGJZT0LMchXiVAo5QeRvauqCv6BsApyycQiGTpAbX0l9V97FANGotB9KRuwstXqZ9tNo9a70-oNJGu8CDsBO2i-mmdNGsCW5QQNGH3z_TtwBq8fX5zYhulc7HMvZr93kfO-zMZUHdeUmUBnqeig0IdCIM-67H1WzAYZ_s86ZMuZLEj5m_VyNas5rbEox4B8GW6aDzQO0YsBbp5jXzfkR0NVNUSip5Q1kTDtK24YbUz9Pt_pmsGof6a_3pSOw_oEAWnHH-C3a4zKQvUBklb9YeGVPv4OQ

Once decoded the payload would look like:

{
  "iss": "https://identity.moneyhub.co.uk",
  "aud": "d9dc9d5e-d190-438c-b658-a4be3779100d",
  "jti": "c9d133e0-e708-402d-a6b7-dc8ff9c29a1c",
  "sub": "5f75a9f947f9bd74d921a6c9",
  "events": {
    "urn:com:moneyhub:events:payment-completed": {
      "paymentId": "dc9446ee-afc1-4b47-bab5-2b01c7da09e3",
      "status": "completed",
      "paymentSubmissionId": "2be8cbe5-e138-43c5-bc58-760cefa89248",
      "submittedAt": "2020-10-01T10:05:45.374Z"
    }
  },
  "iat": 1601546781
}

You'll need to use a JWT library to decode and verify the messages

While you can decode the messages without verifying them, it's better to do both at the same time. In order to verify the message you'll need to retrieve our public signing key

The key is subject to change over time without notice so don't keep it as a static resource

Here is a example written in Node where we retrieve the public signing key to verify the webhook messages:

const got = require("got")
const {JWKS} = require("jose")

const getPublicMoneyhubKeyAsPEM = async () => {
  try {
    const {jwks_uri} = await got("https://identity.moneyhub.co.uk/oidc/.well-known/openid-configuration").json()
    const jwks = await got(jwks_uri).json()
    const signingKey = JWKS.asKeyStore(jwks).get({use: "sig"})
    
    console.log(signingKey.toPEM())
  } catch (e) {
    console.error(e)
  }
}
    
getPublicMoneyhubKeyAsPEM()

This could then be extended to verify and decode the message like so:

const got = require("got")
const {JWKS,JWT} = require("jose")

const decodeAndVerifyMessage = async (message) => {
  try {
    const {jwks_uri} = await got("https://identity.moneyhub.co.uk/oidc/.well-known/openid-configuration").json()
    const jwks = await got(jwks_uri).json()
    const signingKey = JWKS.asKeyStore(jwks).get({use: "sig"})
    const payload = JWT.verify(message, signingKey)

    console.log(payload)
  } catch (e) {
    console.error("Failed to verify the message", e)
  }
}
    
decodeAndVerifyMessage(message)