Tutorial - Interacting with third party payment providers via Glue API
Edit on GitHubThe checkout process of Spryker Glue API can be leveraged to involve third parties in the process of order confirmation. This can be required, for example, when the method of payment selected by the user requires additional steps to complete the purchase. These can include, but not limited to, card validation, processing a bank transfer, etc.
For details, see Checking Out Purchases and Getting Checkout Data.
In this tutorial, you will find out how to invoke third parties in the API payment process.
1. Create new module
To implement third party interactions, first, you need to create a new module or extend an existing one. Let us create one on the Project level. The module needs to interact with 2 layers of Spryker Commerce OS: Glue (API) and Zed (backend). Thus, you need to create the following folders for module MyModule:
src/Pyz/Glue/MyModule
src/Pyz/Zed/MyModule
The module needs to implement 2 plugins:
- A plugin that maps the response of the
/checkout
API endpoint and fills it with the necessary attributes.
The redirectUrl
and isExternalRedirect
attributes are auto-mapped out of the box. If necessary, you can add your own attributes. For example, if a payment system requires a vendor ID for order confirmation, you can create a separate attribute to pass the ID to the API Client.
- A plugin to process the response of the payment service provider. The overall interaction diagram between Glue API, the API Client, and the third party is as follows:
2. Implement Checkout response mapper plugin
First, we need to implement a plugin that maps the checkout response and fills it with the necessary redirect URL and other attributes that are mapped. To do so, create a plugin file on the Glue layer: src/Pyz/Glue/MyModule/Plugin/CheckoutRestApi/CheckoutResponseMapperPlugin.php
.
The plugin must implement the CheckoutResponseMapperPluginInterface
. Using the the mapRestCheckoutResponseTransferToRestCheckoutResponseAttributesTransfer
function of the interface, you can set the redirect URL and specify whether it is an internal or external redirect.
Sample implementation
<?php
namespace Pyz\Glue\MyModule\Plugin\CheckoutRestApi;
use Generated\Shared\Transfer\RestCheckoutResponseAttributesTransfer;
use Generated\Shared\Transfer\RestCheckoutResponseTransfer;
use Spryker\Glue\CheckoutRestApiExtension\Dependency\Plugin\CheckoutResponseMapperPluginInterface;
use Spryker\Glue\Kernel\AbstractPlugin;
class CheckoutResponseMapperPlugin extends AbstractPlugin implements CheckoutResponseMapperPluginInterface
{
/**
* @param \Generated\Shared\Transfer\RestCheckoutResponseTransfer $restCheckoutResponseTransfer
* @param \Generated\Shared\Transfer\RestCheckoutResponseAttributesTransfer $restCheckoutResponseAttributesTransfer
*
* @return \Generated\Shared\Transfer\RestCheckoutResponseAttributesTransfer
*/
public function mapRestCheckoutResponseTransferToRestCheckoutResponseAttributesTransfer(
RestCheckoutResponseTransfer $restCheckoutResponseTransfer,
RestCheckoutResponseAttributesTransfer $restCheckoutResponseAttributesTransfer
): RestCheckoutResponseAttributesTransfer {
$restCheckoutResponseTransfer->getCheckoutResponse()->getRedirectUrl();
$restCheckoutResponseAttributesTransfer
->setIsExternalRedirect($restCheckoutResponseTransfer->getCheckoutResponse()->getIsExternalRedirect())
->setRedirectUrl($restCheckoutResponseTransfer->getCheckoutResponse()->getRedirectUrl());
return $restCheckoutResponseAttributesTransfer;
}
}
3. Implement payload processor plugin
After a user completes payment verification, the payment service provider will submit a payload containing the relevant payment information. The payload will be submitted by the API client to the /order-payments
endpoint.
To process the data, we need to implement another plugin on the Zed layer. The plugin will update the payment information in the database. Create a plugin file as follows: src/Pyz/Zed/MyModule/Communication/Plugin/OrderPaymentsRestApi/OrderPaymentUpdaterPlugin.php
.
The plugin must extend the OrderPaymentUpdaterPluginInterface and implement the following two functions:
isAppplicable
—this function determines whether a specific payment is processed by the plugin. The function returns true if the payment must be processed; otherwise, it returns false.updateOrderPayment
—this function updates the payment data in the database.
To help you understand which payments need to be processed, you can use the optional paymentIdentifier
field in POST requests to the /order-payments
endpoint. To make sure it is always present in a request, you may require the API client to set the field to a specific value to invoke your payment plugin. The value of the field can be retrieved using the getPaymentIdentifier
helper function.
For details, see Updating Payment Data.
Sample implementation
<?php
namespace Pyz\Zed\MyModule\Communication\Plugin\OrderPaymentsRestApi;
use Generated\Shared\Transfer\UpdateOrderPaymentRequestTransfer;
use Generated\Shared\Transfer\UpdateOrderPaymentResponseTransfer;
use Spryker\Zed\Kernel\Communication\AbstractPlugin;
use Spryker\Zed\OrderPaymentsRestApiExtension\Dependency\Plugin\OrderPaymentUpdaterPluginInterface;
class OrderPaymentUpdaterPlugin extends AbstractPlugin implements OrderPaymentUpdaterPluginInterface
{
/**
* @param \Generated\Shared\Transfer\UpdateOrderPaymentRequestTransfer $updateOrderPaymentRequestTransfer
*
* @return bool
*/
public function isApplicable(UpdateOrderPaymentRequestTransfer $updateOrderPaymentRequestTransfer): bool
{
if ($updateOrderPaymentRequestTransfer->getPaymentIdentifier()) {
return true;
}
return false;
}
/**
* @param \Generated\Shared\Transfer\UpdateOrderPaymentRequestTransfer $updateOrderPaymentRequestTransfer
*
* @return \Generated\Shared\Transfer\UpdateOrderPaymentResponseTransfer
*/
public function updateOrderPayment(UpdateOrderPaymentRequestTransfer $updateOrderPaymentRequestTransfer): UpdateOrderPaymentResponseTransfer
{
$payload = $updateOrderPaymentRequestTransfer->getDataPayload();
return (new UpdateOrderPaymentResponseTransfer())
->setIsSuccessful(true)
->setPaymentIdentifier($updateOrderPaymentRequestTransfer->getPaymentIdentifier())
->setDataPayload($updateOrderPaymentRequestTransfer->getDataPayload());
}
}
4. Wire the plugins
Now, you need to wire the plugins so that they could be invoked during checkout. The Checkout Response Mapper Plugin needs to be registered in \Pyz\Glue\CheckoutRestApi\CheckoutRestApiDependencyProvider::getCheckoutResponseMapperPlugins()
:
...
/**
* @return \Spryker\Glue\CheckoutRestApiExtension\Dependency\Plugin\CheckoutResponseMapperPluginInterface[]
*/
protected function getCheckoutResponseMapperPlugins(): array
{
return [
...
new CheckoutResponseMapperPlugin
];
}
...
The Payment Processor Plugin is registered in \Spryker\Zed\OrderPaymentsRestApi\OrderPaymentsRestApiDependencyProvider::getOrderPaymentUpdaterPlugins()
...
/**
* @return \Spryker\Zed\OrderPaymentsRestApiExtension\Dependency\Plugin\OrderPaymentUpdaterPluginInterface[]
*/
protected function getOrderPaymentUpdaterPlugins(): array
{
return [
...
new OrderPaymentUpdaterPlugin
];
}
...
After wiring the plugins, the response of the /checkout
endpoint will contain a correct redirect URL, and the /order-payments
endpoint will process payloads received from the payment provider. Try accessing the endpoints to verify that the plugins process the data.
Thank you!
For submitting the form