Follow

Properly Receiving Webhooks

PayJunction wants to make sure that when a webhook is issued it is correctly received by the server. If PayJunction does not receive a valid success status from the server it assumes something went wrong and the data was not delivered, so it tries again and again until either the webhook is successfully received, or the max time limit is reached.

To notify the PayJunction webhook service that the data was successfully received and processed a successful HTTP status code needs to be returned by the webhook listening service. Refer to the documentation for the library handling the HTTP communication for the proper way to set the status code.

The best practice is to send the response with the successful status code as soon as the data has been verified, before performing any processes which can delay the response, such as updating a database or making an asynchronous call to another service. This will help minimize the chance that the response is not received in time to prevent a duplicate webhook from being sent by PayJunction. See the example below for more details.

Example ExpressJS Webhook Listener Implementation

var express = require('express');
var router = express.Router();
var mongo = require('mongodb'); // Routing path for webhook listener. Webhook payloads sent by PJ use the POST method. router.post('/st-transactions', function(request, response) { var statusSent = false; // Verify we have the necessary information to process the webhook try { var requestPaymentId = request.body['data']['requestPaymentId']; var smartterminalId = request.body['data']['smartTerminalId']; var transactionId = request.body['data']['transactionId']; if (requestPaymentId && smartterminalId && transactionId) { response.sendStatus(200); // Success statusSent = true; } else { response.sendStatus(400); // Bad Request, need PJ to try sending again statusSent = true; throw new Error("Invalid data in webhook payload: " + JSON.stringify(request.body)); } // Perform high-latency tasks such as updating the database // and updating end user interface after sending success response to PJ mongo.get('pending').remove({requestPaymentId}); getTransactionDetails(transactionId, function(details) { updateFrontEndUI({"id": requestPaymentId, "status": details['status'], "code": details['response']['code']}); }); } catch (ex) { console.log(ex.message); if (!statusSent) response.sendStatus(500); // Internal error } });