Skip to content

Ktor Webhook

Ron June Valdoz edited this page Sep 26, 2024 · 1 revision

Signature verification to make sure that the request is coming from your client.

val webhookSecretKey = "" // created webhook secret key

// http://localhost/paymongo/events
fun Route.payMongo() {
   route("paymongo") {
      post("events") {
         processWebhookEvent(call)
      }
   }
}
// sample webhook process
// see instruction how to secure webhook 
// https://developers.paymongo.com/docs/creating-webhook#3-securing-a-webhook-optional-but-highly-recommended
suspend fun processWebhookEvent(call: ApplicationCall) {
   val jsonString = call.receiveText()
   val webhookEvent = AppJson.decodeFromString<ReceiveWebhookEvent>(jsonString)
   val signature = call.request.header("Paymongo-Signature")
   if (signature == null) {
      call.respond(HttpStatusCode.Unauthorized, "Missing Paymongo-Signature")
   } else {
      // signature verification
      val sign = signature.split(",")
      val t = sign[0].replace("t=", "").toLong() // timestamp
      val te = sign[1].replace("te=", "") // test mode
      val li = sign[2].replace("li=", "") // live mode
      val attributes = webhookEvent.data.attributes
      val liveMode = attributes.liveMode
      val signatureFromPayload = "$t.$jsonString"
      val signatureFromHeader = if (liveMode) {
         li
      } else {
         te
      }
      // hash signature
      val hashedSignature = hash(content = signatureFromPayload, key = webhookSecretKey, algorithm = "HmacSHA256")
      // check for a matching signature
      if (hashedSignature == signatureFromHeader) {
         // process event response here
         when (val data = attributes.data) {
            is Source -> {}
            is Payment -> {}
            else -> {}
         }
         call.respond(HttpStatusCode.OK, "Webhook OK")
      } else {
         call.respond(HttpStatusCode.Unauthorized, "Invalid signature")
      }
   }
}
Clone this wiki locally