Adding a Payment Service Provider

📘

This is an article for advanced users of Frontastic.

In this article, we'll give you an overview and a basic guide to integrating Payment Service Providers (PSP) with Frontastic. PSP integrations require you to write backend and frontend code and are usually a challenge to verify.

The essence

From an API point of view, the task is trivial: Some backend endpoint must add payments to the cart which cover the cart sum. The API call to do so is pretty straight forward and a full controller action could look like the below. (See how to register a controller using custom endpoints).

public function addPayment(Context $context, Request $request): array
{
    $payload = $this->getJsonContent($request);
    $cartApi = $this->getCartApi($context);
    $cart = $this->getCart($context, $request);

    $cartApi->startTransaction($cart);
    $cartApi->addPayment(
        $cart,
        new Payment([
            'paymentProvider' => 'frontastic',
            'paymentMethod' => 'invoice',
            'paymentId' => $payload['paymentId'],
            'amount' => $payload['sum'] ?? $cart->sum,
            'currency' => $cart->currency,
            'paymentStatus' => Payment::PAYMENT_STATUS_PENDING,
        ])
    );
    return ['cart' => $cartApi->commit($context->locale)];
}

But before adding a payment to the cart, we must make sure that the payment is valid and the user is charged the correct amount by the PSP. If your ERP processes all payments, you could use an implementation like the one above.

The flow

Frontastic itself doesn't store any payment-related data. And payment-related data isn't supposed to be stored in any systems owned by Frontastic.

This means that usually in the last step of the checkout, the customer will be redirected to the website of the PSP to enter their data. The entry point could be an IFrame from the PSPs servers or a redirect right away. Once the PSP has collected and verified all necessary information, the user will be redirected back to Frontastic. This Frontastic redirect endpoint should then verify and store the payment in the cart, as described above.

Red elements are by the PSP, blue elements are in the Frontastic stackRed elements are by the PSP, blue elements are in the Frontastic stack

Red elements are by the PSP, blue elements are in the Frontastic stack

After the controller has redirected back to the cart after adding the payment, the checkout can display the "Order" button to finalize the checkout (convert the cart to an order). Optionally the controller can also implement the cart to order conversion and redirect directly to the order success page:

// Add payment after verification against PSP secret

// Check if payments are sufficient for cart
if (!$cart->isReadyForCheckout()) {
    // If not fully paid redirect to cart overview
    return new RedirectRoute('Frontastic.Frontend.Master.Checkout.cart');
}

// If fully paid, convert to order and redirect to success page
$order = $cartApi->order($cart, $context->locale);
return new RedirectRoute(
    'Frontastic.Frontend.Master.Checkout.finished',
    ['order' => $order->orderId, 'token' => ...]
);

If you want to see a full example of such an extension, take a look at our Adyen PSP integration or the steps to creating a checkout article.

PSP credentials

The configuration of the PSP, including the credentials, should be put into your project.yml (see project configuration). This allows customers to use different credentials for development, staging, and live systems. Since multiple PSPs might be used in parallel, each PSP integration should register a unique key inside the payment configuration object. For example, the configuration for the Adyen integration is inside the payment.adyen object. The concrete structure of the configuration options is specific to the PSP. There's no common structure that needs to be followed.

Error handling

Testing and debugging the payment process and especially the different error handling scenarios can be challenging. It can be helpful to build a very basic Frontastic componentFrontastic component - A customizable building block that's used together with other components to create a commerce site. Known as `tastic` for short in code. for testing the backend implementation. This basic Frontastic componentFrontastic component - A customizable building block that's used together with other components to create a commerce site. Known as `tastic` for short in code. can then later be transformed into the final checkout Frontastic componentFrontastic component - A customizable building block that's used together with other components to create a commerce site. Known as `tastic` for short in code.. Because of security implications, PSPs tend to not report useful error messages but just report that something went wrong. This can be a challenge during the development of the integration.

But unfortunately, testing all different error scenarios will be a very time-consuming task for most PSPs.

If a user aborts the redirects from the PSP to Frontastic or their connection drops (for example, on mobile data), Frontastic won't be informed about the payment but the user might still be charged. While this doesn't happen very often, you should make sure that your order management system checks for open carts where a successful payment has been made and convert them to orders using your order management system or refund the payment from there. Frontastic doesn't implement background jobs to fix this automatically.


Did this page help you?