Laravel Skrill Payment Gateway Integration with LaraSkrill

Today, I'm going to show how to integrate Skrill payment gateway in Laravel with LaraSkrill package. By using this package we are able to make payment and do refund. So, let's start:

Note: Last tested on Laravel 9.42.2

Table of Contents

  1. Install LaraSkrill Package
  2. Make Migration, Model and Controller
  3. Register Routes
  4. Create Blade Templates
  5. Test Project
  6. Note

Step 1 : Install LaraSkrill Package

At first, let's install LaraSkrill package by typing this command:

composer require obydul/laraskrill

(Optional) Now we have to register LaraSkrill provider. Go to config >> app.php and find the providers & add this:

app.php
'providers' => [
    // ...
    Obydul\LaraSkrill\LaraSkrillServiceProvider::class,
]

Step 2 : Make Migration, Model and Controller

We are going to create migration, model and controller for Skrill payment. Run this artisan command to create the three things:

php artisan make:model SkrillPayment -mc

The migration file is for Skrill IPN. Like PayPal, Skrill provides Instant Payment Notification (IPN) too. To save payment information, we use IPN. If you don't need to save payment information in your database, then you don't this need.

Go to database>migrations and open the newly created migration file. Then paste this code:

timestamp_create_skrill_payments_table.php
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('skrill_payments', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('transaction_id');
            $table->string('mb_transaction_id');
            $table->string('invoice_id')->nullable();
            $table->string('order_from')->nullable();
            $table->string('customer_id')->nullable();
            $table->string('customer_email')->nullable();
            $table->string('biller_email');
            $table->float('amount');
            $table->string('currency');
            $table->string('status');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('skrill_payments');
    }
};

Now open SkrillPaymentController from app>Http>Controllers and paste this code:

SkrillPaymentController.php
<?php

namespace App\Http\Controllers;

use App\Models\SkrillPayment;
use Illuminate\Http\Request;
use Obydul\LaraSkrill\SkrillClient;
use Obydul\LaraSkrill\SkrillRequest;
use Illuminate\Support\Facades\Redirect;

class SkrillPaymentController extends Controller
{
    /**
     * Construct.
     */
    private $skrilRequest;

    public function __construct()
    {
        // skrill config
        $this->skrilRequest = new SkrillRequest();
        $this->skrilRequest->pay_to_email = '[email protected]';
        $this->skrilRequest->return_url = 'https://laraskrill.test/payment-completed';
        $this->skrilRequest->cancel_url = 'https://laraskrill.test/payment-cancelled';
        $this->skrilRequest->logo_url = 'https://cdn.shouts.dev/images/shoutsdev.png';
        $this->skrilRequest->status_url = 'your email or ipn url'; // you can use https://webhook.site webhook url as IPN. It is a free service to test webhook.
        // $this->skrilRequest->status_url2 = 'your email or ipn url';
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function index()
    {
        $payments = SkrillPayment::query()->orderBy('id', 'desc')->get();

        return view('home', compact('payments'));
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function paymentCompleted()
    {
        return view('payment-completed');
    }

    /**
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
     */
    public function paymentCancelled()
    {
        return view('payment-cancelled');
    }

    /**
     * Make Payment
     */
    public function makePayment()
    {
        // create object instance of SkrillRequest
        $this->skrilRequest->prepare_only = 1;
        $this->skrilRequest->amount = '10.50';
        $this->skrilRequest->currency = 'USD';
        $this->skrilRequest->language = 'EN';

        // custom fields (optional)
        $this->skrilRequest->merchant_fields = 'site_name, invoice_id, customer_id, customer_email';
        $this->skrilRequest->site_name = 'Shout.dev';
        $this->skrilRequest->invoice_id = 'INV_' . strtoupper(str()->random(10));
        $this->skrilRequest->customer_id = 1001;
        $this->skrilRequest->customer_email = '[email protected]';

        $this->skrilRequest->detail1_description = 'Product ID:';
        $this->skrilRequest->detail1_text = '101';

        // create object instance of SkrillClient
        $client = new SkrillClient($this->skrilRequest);
        $sid = $client->generateSID(); //return SESSION ID

        // handle error
        $jsonSID = json_decode($sid);
        if ($jsonSID != null && $jsonSID->code == "BAD_REQUEST")
            return $jsonSID->message;

        // do the payment
        $redirectUrl = $client->paymentRedirectUrl($sid); //return redirect url
        return Redirect::to($redirectUrl); // redirect user to Skrill payment page
    }

    /**
     * Do Refund
     */
    public function doRefund()
    {
        // Create object instance of SkrillRequest
        $prepare_refund_request = new SkrillRequest();
        // config
        $prepare_refund_request->email = 'merchant_email';
        $prepare_refund_request->password = 'api_password';
        $prepare_refund_request->refund_status_url = 'refund_status_url';
        // request
        $prepare_refund_request->transaction_id = 'MNPTTX0001';
        $prepare_refund_request->amount = '5.56';
        $prepare_refund_request->refund_note = 'Product no longer in stock';
        $prepare_refund_request->merchant_fields = 'site_name, customer_email';
        $prepare_refund_request->site_name = 'Your Website';
        $prepare_refund_request->customer_email = '[email protected]';

        // do prepare refund request
        $client_prepare_refund = new SkrillClient($prepare_refund_request);
        $refund_prepare_response = $client_prepare_refund->prepareRefund(); // return sid or error code

        // refund requests
        $refund_request = new SkrillRequest();
        $refund_request->sid = $refund_prepare_response;

        // do refund
        $client_refund = new SkrillClient($refund_request);
        $do_refund = $client_refund->doRefund();
        dd($do_refund); // response
    }

    /**
     * Instant Payment Notification (IPN) from Skrill
     */
    public function ipn(Request $request)
    {
        // skrill data - get more fields from Skrill Quick Checkout Integration Guide 7.9 (page 23)
        $transaction_id = $request->transaction_id;
        $mb_transaction_id = $request->mb_transaction_id;
        $biller_email = $request->pay_from_email;
        $amount = $request->amount;
        $currency = $request->currency;
        $status = $request->status;

        // custom fields
        $invoice_id = $request->invoice_id ?? null;
        $order_from = $request->site_name ?? null;
        $customer_id = $request->customer_id ?? null;
        $customer_email = $request->customer_email ?? null;

        // status message
        if ($status == '-2') {
            $status_message = 'Failed';
        } else if ($status == '2') {
            $status_message = 'Processed';
        } else if ($status == '0') {
            $status_message = 'Pending';
        } else if ($status == '-1') {
            $status_message = 'Cancelled';
        }

        // now store data to database
        $skrill_ipn = new SkrillPayment();
        $skrill_ipn->transaction_id = $transaction_id;
        $skrill_ipn->mb_transaction_id = $mb_transaction_id;
        $skrill_ipn->invoice_id = $invoice_id;
        $skrill_ipn->order_from = $order_from;
        $skrill_ipn->customer_email = $customer_email;
        $skrill_ipn->biller_email = $biller_email;
        $skrill_ipn->customer_id = $customer_id;
        $skrill_ipn->amount = $amount;
        $skrill_ipn->currency = $currency;
        $skrill_ipn->status = $status_message;
        $skrill_ipn->created_at = Date('Y-m-d H:i:s');
        $skrill_ipn->updated_at = Date('Y-m-d H:i:s');
        $skrill_ipn->save();
    }
}

In the SkrillPaymentController, these three are the major functions.

  • makePayment(): to make a payment
  • doRefund(): to send refund
  • ipn(): to receive payment information from Skrill

Step 3 : Register Routes

Let's define the routes for our project. Open web.php from routes folder and paste this routes:

web.php
<?php

use App\Http\Controllers\SkrillPaymentController;
use Illuminate\Support\Facades\Route;

Route::get('/', [SkrillPaymentController::class, 'index']);
Route::get('/payment-completed', [SkrillPaymentController::class, 'paymentCompleted']);
Route::get('/payment-cancelled', [SkrillPaymentController::class, 'paymentCancelled']);

Route::get('/make-payment', [SkrillPaymentController::class, 'makePayment']);
Route::get('/do-refund', [SkrillPaymentController::class, 'doRefund']);
Route::post('/ipn', [SkrillPaymentController::class, 'ipn']);

Step 4 : Create Blade Templates

We have defined 3 views on the routes. Let's make the blade flies. Go to resources/views folder make 4 blade files like below:

layout.blade.php
<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="icon" href="{{ asset('icon.png') }}">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">

    <title>@yield('title')</title>
</head>
<body>

<div class="container">
    <div class="text-center mt-5">
        <a href="https://shouts.dev/" target="_blank">
            <img src="{{ asset('logo.png') }}" alt="logo"><br>
        </a>
        <span class="text-secondary">Laravel Skrill Integration with LaraSkrill</span>
    </div>

    <div class="mt-3">
        @yield('content')
    </div>
</div>

</body>
</html>
home.blade.php
@extends('layout')

@section('title', 'LaraSkrill - Shouts.dev')

@section('content')
    <div class="text-center" style="margin-bottom: 25px;">
        <a href="{{url('make-payment')}}" class="btn btn-info">Make Payment</a>
        <a href="{{url('do-refund')}}" class="btn btn-danger">Do Refund</a>
    </div>

    <table class="table table-bordered">
        <thead>
        <tr>
            <th scope="col">#</th>
            <th scope="col">MB Transaction ID</th>
            <th scope="col">Amount</th>
            <th scope="col">Customer Email</th>
            <th scope="col">Created At</th>
        </tr>
        </thead>
        <tbody>
        @if(!empty($payments))
            @foreach($payments as $payment)
                <tr>
                    <td>{{ $payment->id }}</td>
                    <td>{{ $payment->mb_transaction_id }}</td>
                    <td>{{ $payment->amount }} ({{ $payment->currency }})</td>
                    <td>{{ $payment->customer_email }}</td>
                    <td>{{ $payment->created_at->format('d M, Y - H:i A') }}</td>
                </tr>
            @endforeach
        @endif
        </tbody>
    </table>
@endsection
payment-completed.blade.php
@extends('layout')

@section('title', 'Payment Completed')

@section('content')
    <div class="alert alert-success" role="alert">
        Payment Successfully Completed!
    </div>

    <div class="text-center">
        <a href="{{ url('/') }}" class="btn btn-info">&lt;Home</a>
    </div>
@endsection
payment-cancelled.blade.php
@extends('layout')

@section('title', 'Payment Cancelled')

@section('content')
    <div class="alert alert-danger" role="alert">
        Payment Has Been Cancelled!
    </div>

    <div class="text-center">
        <a href="{{ url('/') }}" class="btn btn-info">&lt;Home</a>
    </div>
@endsection

Step 5 : Test Project

We have completed all the steps. It's time to test our project. My test project's local URL is https://laradev.test/.

Run the project and visit make payment route:

https://laraskrill.test/make-payment

If everything is correct, you will be redirected to the payment page. You can choose any payment method. Skrill test VISA card number: 4000001234567890. You'll find more test cards on the GitHub repo.

I'm going to select the Paysafecard method (no need Paysafecard account for testing purposes). To see the Paysafecard method, please change the country to the USA.

After selecting Paysafecard, you'll see this screen. Now just enter your email here.

After enterting your email, click on the 'Go to paysafecard' button and the payment will be completed.

Success..! You can click the continue button or it will automatically redirect to your return URL.

I've set IPN and received data from Skrill and stored in the database.

Note: IPN doesn't work in localhost. For localhost, please test with email.

** To do refund, you have to add your IP in white-list. The option is in Skrill settings. You need to generate MQI/API password too.

We have successfully integrated Skrill payment gateway in Laravel using LaraSkrill. You can download this project from GitHub.

Step 6 : Note

I've created this LaraSkrill package. You will find more information on GitHub. If you notice any issues, please write in the comment section. Thank you. ๐Ÿ™‚


Software Engineer | Ethical Hacker & Cybersecurity...

Md Obydullah is a software engineer and full stack developer specialist at Laravel, Django, Vue.js, Node.js, Android, Linux Server, and Ethichal Hacking.