Integration of Fondy (3rd party service) webhooks using QuickMocker and its Local Forwarder
So you are a developer and you’ve got yet another task to integrate some 3rd party into your app? E.g. some payment system like Stripe, PayPal or maybe some meeting rooms like Zoom, GoTo or whatever else you can imagine to integrate? Nowadays all of such services provide API not only as an interface for receiving requests from clients (e.g. your web app), but also they can make reverse requests to your app in order to notify the client immediately about some event on the 3-rd party side. This kind of reverse requests as you might guess already are called Webhooks.
As a sample we will be integrating Fondy (a payment service provider) into our app. Particularly in this sample we need to integrate the instant notification (webhook) to our application about payment completion. On the server side we will use PHP code samples and on the client side it will be Javascript.
But first of all you’ll need to register your Fondy account. Then go to the Merchant Settings and grab your Merchant ID and Payment Key (also called “secret key” in the API doc):
Secondly go and get a free QuickMocker account. Create a new project with a suggested random subdomain. Go inside the project and copy your endpoint (subdomain) URL:
Please note that by default the initial wildcard endpoint can intercept any request made to any URL of the project. It will respond with 404 status code by default, but you can change this behavior if you want.
Now we will build a simple PHP web service (or simply script) with the help of Fondy PHP SDK (v2) that will generate for us a one-time token that we’ll use for creating a payment form. In case you use composer, you can add Fondy PHP SDK using this command:
composer require cloudipsp/php-sdk-v2
Alternatively you might download or clone it. See yourself more here: https://packagist.org/packages/cloudipsp/php-sdk-v2
Later we will use this token to securely generate order form on the client side using Fondy JavaScript SDK. Huh… a lot of words which might sound as a non-sense :) But I hope they will start making sense if you look at the code sample below:
<?phpinclude 'vendor/autoload.php'; // in case you use composeruse Cloudipsp\Configuration;
use Cloudipsp\Checkout;Configuration::setMerchantId('<fondyMerchantID>');
Configuration::setSecretKey('<fondyPaymentKey>');
Configuration::setApiVersion('2.0');$request = [
'order_id' => time(),
'currency' => 'USD',
'merchant_id' => '<fondyMerchantID>',
'order_desc' => 'QuickMocker Test Order',
'product_id' => 'test',
'amount' => 1, // equals 1 cent
'required_rectoken' => 'Y', // might use this if you want to charge your customers later without customer interaction, e.g. for recurring payments
'server_callback_url' => 'https://qafu2mppt7.api.quickmocker.com', // this is where our QuickMocker endpoint gets inserted, change it to your own.
];$response = Checkout::token($request);
$data = $response->getData();
echo $data['token'];
So the script above generates for us a one-time token that we can use in order to create a payment form in the client app. This form will already get the payment amount that we have set on the server side (so nobody can replace it in the client app). But the main thing is that this payment is linked with our internal order ID and product ID which again cannot be hijacked.
Now lets create a simple JS client app which we can try out on some online service like JsFiddle, where we’ll use our token generated by the PHP script we had written above. You might customize the look of the payment form using CSS. You can even hide some fields like email, in case you do not want allowing user to change it (remember we have an order ID which can be linked with the user and its email in our app’s database).
So, first of all you have to include following JS and CSS file in your app provided by Fondy CDN:
https://pay.fondy.eu/latest/checkout.js
https://pay.fondy.eu/latest/checkout.css
And below are all the parts of the app, separately (HTML, JS and CSS):
HTML Part:
<!-- Only one container needed to place the fondy payment form -->
<div id="checkout-container"></div>
JavaScript Part:
var options = {
options: {
fullScreen: true,
fee: true,
title: 'QuickMocker Test',
email: true,
link: 'https://quickmocker.com',
tooltip: true,
},
params: {
token: '7d6c8299fc906793fc1b3036dc9722d826eb3b60', // place your token here to see checkout form instead of payment is approved
email: 'your.email@testemail.com',
},
};window.fondy('#checkout-container', options).$on("success", (model) => {
var order_status = model.attr("order.order_data.order_status");
if (order_status == "approved") {
alert('Your payment was successfully processed.');
}
}).$on("error", function (model) {
var response_description = model.attr("error.message");
alert('There was a problem with your payment. Details: ' + response_description);
});
CSS Part:
/* Sample styles for the fondy payment form */
.f-header {
background: #d5ecff;
}
.f-wrapper {
background: #daf7d8 !important;
}
All of the parts together on the JSFiddle here:
https://jsfiddle.net/wf64gbr2/
In order to make a payment, lets use test credit cards, which you may find at this URL: https://docs.fondy.eu/en/docs/page/2/ . Copy the card number, provide any month, year and CVV code you want and hit Pay Now button.
Right after the payment is completed successfully, QuickMocker endpoint immediately receives a request (webhook) from Fondy:
Click on the Requests Log tab, and you’ll see the list of the requests that was done to your endpoint. Unfold the top request which is the latest as on the screenshot:
By the way, we did not add any custom endpoint to receive Fondy webhooks, so it is intercepted by QuickMocker using the initial wildcard endpoint which responds with 404 status code by default. Because of this Fondy might send to you several webhook requests with the same payment result data. You can add another endpoint for the Fondy webhook or else simply change status code of the initial endpoint to 200.
Anyway, as you can see on the screenshot above, the data is sent as a base64. If you decode it you will see a JSON similar to this:
{
"order":{
"rrn":"",
"masked_card":"444455XXXXXX6666",
"sender_cell_phone":"",
"response_status":"success",
"sender_account":"",
"fee":"",
"rectoken_lifetime":"01.01.2034 00:00:00",
"reversal_amount":"0",
"settlement_amount":"0",
"actual_amount":"8442",
"order_status":"approved",
"response_description":"",
"verification_status":"",
"order_time":"24.09.2020 17:41:32",
"order_id":"1600980123",
"parent_order_id":"",
"merchant_data":"",
"tran_type":"purchase",
"eci":"7",
"settlement_date":"",
"payment_system":"card",
"rectoken":"e07e0989bcdffaa446909438b367c136cc90bac7",
"approval_code":"478450",
"merchant_id":1436164,
"settlement_currency":"",
"payment_id":272767812,
"product_id":"test",
"currency":"USD",
"card_bin":444455,
"response_code":"",
"card_type":"VISA",
"amount":"1",
"sender_email":"your.email@testemail.com"
}
}
In order to make sure that this data is not spoofed, we need to validate it against the signature which was sent inside the webhook along with the data.
<?phpinclude 'vendor/autoload.php'; // in case you use composeruse Cloudipsp\Configuration;
use Cloudipsp\Response\Response;$requestBody = file_get_contents('php://input');
$requestData = json_decode($requestBody, true);Configuration::setMerchantId('<fondyMerchantID>');
Configuration::setSecretKey('<fondyPaymentKey>');
Configuration::setApiVersion('2.0');$response = new Response([
'response' => json_encode([
'response' => $requestData,
], 320),
]);if (!$response->isValid()) {
print "Error: Invalid data";
} else {
$order = $response->getData();
print "Success: Order ID: " . $order['order_id'];
}
So we have successfully captured the webhook from 3-rd party service using QuickMocker API mocking tool. Knowing the webhook request data allows us to create a proper web service that can handle this data and complete our order on the server side of the app (e.g. mark the order in the database as paid, save the `rectoken` for possible future charges of the customer etc). So such API mocking tools like QuickMocker are very helpful in a reverse integration with 3-rd parties without having to put our app into public, which means our app does not need to have some public DNS or IP address during the development stage.
The only inconvenience here you might think is that if we want to test our code, we still have to mimic the request to our local server app with that data captured by QuickMocker using some tool like Postman which adds a bit of overhead here in a form of a manual intervention during the testing. But wait… except of capturing requests from remote services, QuickMocker can also work as a local client forwarder, which means while QuickMocker is opened in your browser and while it receives the requests from the outside, it can also forward those requests to your “localhost” server app.
How to setup forwarder? Simply set your local development server app URL, which will receive the payment completion webhook from the fondy (e.g. http://localhost/fondy-payment-completed). To do this click on the Set Local Forwarder button:
And in the modal provide URL. Note: in case your development server app is using insecure protocol (HTTP), you will need to allow this in your browser settings. Read more about allowing your browser to send HTTP request from HTTPS site here: https://docs.adobe.com/content/help/en/target/using/experiences/vec/troubleshoot-composer/mixed-content.html
Click Set and you are done. Now the requests will be forwarded to your local app URL and you are all set to receive webhooks directly to your app while developing, debugging, testing and so on. Please note that Local Forwarder URL won’t be saved with your project. As soon as you leave the Requests Log tab, the URL will be gone. So you will have to set it once again if you want to continue “forwarding”.
BTW, there’s a small FAQ which should provide all info you need for Local Forwarder usage: https://quickmocker.com/faq#forwarder
Finally, after you set Local Forwarder URL, you’ll also notice another tab Forwarder Response in the request panel:
Our app has received a forwarded webhook and we can also preview the response of our app in the additional tab as on the screenshot above.
To sum up: an API mocking (fake) tools like QuickMocker could be really helpful while integrating 3rd party services and particularly reverse requests called webhooks. With the help of Local Forwarder feature that is provided by QuickMocker, the integration of webhooks becomes even more seamless without any need to make your local server application public to the world.