Lunar is a Laravel e-commerce package which provides functionalities similar to well-known e-commerce platforms like Shopify. It’s aiming to assist the developers in creating e-commerce shop using Laravel easily. It is claimed that the developers will only need to create the storefront, as they have provided the backend of the e-commerce system.
Although they had constructed the backbone of the system, but they also allow the developers to extend the backend for more functionality. These are usually been done through a mechanism called pipeline, where developers just need to create a new pipeline and add it into the configuration. Developers can benefit from this customization as they can add more custom functions to secure the e-commerce store. For example, the developers can use any fraud validation API to validate the order before it proceeds to the payment stage.
In this tutorial, we are going to show how to call the FraudLabs Pro Screen Order API to validate the order in real-time, and also reject the order if the validation status is REJECT. If you are interested to get more information about the API, you can always refer to its documentation.
Before we get started, make sure that you have a FraudLabs Pro API key with you. If you don’t, you can always register for a free API key to get started. This tutorial will also assume that you had already installed and setup Lunar in your machine. If you haven’t, the simplest way to get it is to follow their installation instructions in their documentation to get started.
Steps to use FraudLabs Pro API in Lunar
- CD into your Lunar project in command prompt, and run the following command to generate a new pipeline class:
php artisan make:class ValidateOrderFraud
. - Open the generated app/ValidateOrderFraud.php file, and replaced the contents with the following code:
<?php namespace App; use Closure; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Http; class ValidateOrderFraud { /** * Create a new class instance. */ public function __construct() { // } /** * Handle the incoming order. * * @param mixed $order * @param \Closure $next * @return mixed */ public function handle($order, Closure $next) { $billingDetails = $order->addresses->firstWhere('type', 'billing'); $shippingDetails = $order->addresses->firstWhere('type', 'shipping'); // Fetch the country code for billing $billingCountryId = $billingDetails->country_id ?? null; $billingCountryIso = $billingCountryId ? DB::table('lunar_countries')->where('id', $billingCountryId)->value('iso2') : $billingCountryId; // Fetch the country code for shipping $shippingCountryId = $shippingDetails->country_id ?? null; $shippingCountryIso = $shippingCountryId ? DB::table('lunar_countries')->where('id', $shippingCountryId)->value('iso2') : $shippingCountryId; $total = $order->total->value; $decimalPlaces = $order->total->currency->decimal_places; // Format the total using the decimal places $formattedTotal = number_format($total / pow(10, $decimalPlaces), $decimalPlaces, '.', ''); $payloads = [ 'key' => env('FRAUDLABSPRO_API_KEY'), 'format' => 'json', // Billing information 'first_name' => $billingDetails->first_name, 'last_name' => $billingDetails->last_name, 'username_hash' => $billingDetails->line_one, 'email' => $billingDetails->contact_email, 'bill_addr' => $billingDetails->line_one, 'bill_city' => $billingDetails->city, 'bill_zip_code' => $billingDetails->postcode, 'bill_country' => $billingCountryIso, // Order information 'user_order_id' => $order->id, 'amount' => $formattedTotal, 'quantity' => $order->total->unitQty, 'currency' => $order->total->currency->code, // Shipping information 'ship_first_name' => $shippingDetails->first_name, 'ship_last_name' => $shippingDetails->last_name, 'ship_addr' => $shippingDetails->line_one, 'ship_city' => $shippingDetails->city, 'ship_zip_code' => $shippingDetails->postcode, 'ship_country' => $shippingCountryIso, ]; // Fill in values if they are not null if ($billingDetails->state !== null) { $payloads['bill_state'] = $billingDetails->state; } if ($billingDetails->contact_phone !== null) { $payloads['user_phone'] = $billingDetails->contact_phone; } if ($shippingDetails->state !== null) { $payloads['ship_state'] = $shippingDetails->state; } if ($order->notes !== null) { $payloads['user_order_memo'] = $order->notes; } // FraudLabs Pro API endpoint $url = 'https://api.fraudlabspro.com/v2/order/screen'; // Make the API request $response = Http::post($url, $payloads); if ($response->successful()) { $result = $response->json(); // Check the fraudlabspro_status if (isset($result['fraudlabspro_status']) && $result['fraudlabspro_status'] === 'REJECT') { // Terminate the pipeline by throwing an exception abort(403, 'Order has been rejected. Please try again later.'); } } else { Log::error('FraudLabs Pro API request failed', ['response' => $response->body()]); } // Continue to the next pipeline stage return $next($order); } }
- After that, go to the config/lunar/orders.php, find the pipelines=>creation array, and add the following line into the last order of the line:
\App\ValidateOrderFraud::class,
. - Double check the modification to make sure the newly added line is at the last order, for example, here is how it may look like:
'pipelines' => [ 'creation' => [ Lunar\Pipelines\Order\Creation\FillOrderFromCart::class, Lunar\Pipelines\Order\Creation\CreateOrderLines::class, Lunar\Pipelines\Order\Creation\CreateOrderAddresses::class, Lunar\Pipelines\Order\Creation\CreateShippingLine::class, Lunar\Pipelines\Order\Creation\CleanUpOrderLines::class, Lunar\Pipelines\Order\Creation\MapDiscountBreakdown::class, \App\ValidateOrderFraud::class, ],
- Finally, add your FraudLabs Pro API key into your .env file like this:
FRAUDLABSPRO_API_KEY=YOUR_API_KEY
. Now your e-commerce shop should be able to validate the order and reject the transaction if fraudulent. For example, here is how it may look like if the API found the order to be suspicious and thus reject it: