PHPackages                             aghfatehi/laravel-tabby - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. aghfatehi/laravel-tabby

ActiveLibrary[Payment Processing](/categories/payments)

aghfatehi/laravel-tabby
=======================

Tabby Pay in 4 Payment Gateway Integration for Laravel - Buy Now Pay Later (BNPL) solution supporting Saudi Arabia, UAE, and Kuwait.

v1.2.0(1mo ago)08MITPHPPHP ^8.1

Since May 30Pushed 1mo agoCompare

[ Source](https://github.com/aghfatehi/laravel-tabby)[ Packagist](https://packagist.org/packages/aghfatehi/laravel-tabby)[ RSS](/packages/aghfatehi-laravel-tabby/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (14)Versions (5)Used By (0)

Laravel Tabby Pay in 4 Payment Gateway
======================================

[](#laravel-tabby-pay-in-4-payment-gateway)

[![Latest Version](https://camo.githubusercontent.com/cbf95c5b4d7bb7717ab99fdc86d6d51148c2c91718c2e0d1f047c994881a4d4a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6167686661746568692f6c61726176656c2d74616262792e737667)](https://packagist.org/packages/aghfatehi/laravel-tabby)[![Laravel](https://camo.githubusercontent.com/1d4df8c9d8bf1a1465f577903a42fcb626084557c088724af28821792b65b734/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31307e31332d7265642e737667)](https://laravel.com)[![PHP](https://camo.githubusercontent.com/45d36955804bf3f4f17097b05a7f41a28e578dc24e0d3ad0d21ae9d9762f44c6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312b2d626c75652e737667)](https://php.net)[![License](https://camo.githubusercontent.com/414bb3a3fda590fe36fd7aacbfdfa63212541d510d6cb358b6308521967e7066/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6167686661746568692f6c61726176656c2d7461626279)](LICENSE)[![Total Downloads](https://camo.githubusercontent.com/8c56dca4f9c8176a37deba332647151ee78502ff3928079b494af3bc38d05663/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6167686661746568692f6c61726176656c2d74616262792e737667)](https://packagist.org/packages/aghfatehi/laravel-tabby)

A professional Laravel package for integrating **Tabby Pay in 4** - the leading Buy Now Pay Later (BNPL) solution in the Middle East. Supports Saudi Arabia, UAE, and Kuwait.

Customers can split their payments into 4 interest-free installments, increasing conversion and average order value.

Features
--------

[](#features)

- ✅ Full Tabby Checkout flow (Create Session, Callback, Cancel, Failure)
- ✅ Capture authorized payments
- ✅ Refund payments (partial or full)
- ✅ Payment details retrieval
- ✅ Webhook management (authorized, captured, failed, rejected)
- ✅ Sandbox &amp; Production environments
- ✅ Multi-region support (SA, AE, KW)
- ✅ Multi-currency support (SAR, AED, KWD)
- ✅ Arabic &amp; English language support
- ✅ Native PHP cURL client (no external HTTP dependencies)
- ✅ Configurable routes prefix &amp; middleware
- ✅ Transaction logging migration
- ✅ Laravel 10, 11, 12 &amp; 13 compatible
- ✅ PHP 8.1+

Requirements
------------

[](#requirements)

LaravelPHPPackage Version10.x^8.1^1.011.x^8.2^1.012.x^8.2^1.013.x^8.2^1.0Installation
------------

[](#installation)

```
composer require aghfatehi/laravel-tabby
```

Configuration
-------------

[](#configuration)

### 1. Publish Configuration

[](#1-publish-configuration)

```
php artisan vendor:publish --tag=tabby-config
```

### 2. Publish Migration (Optional)

[](#2-publish-migration-optional)

```
php artisan vendor:publish --tag=tabby-migrations
php artisan migrate
```

### 3. Environment Variables

[](#3-environment-variables)

Add these to your `.env` file:

```
# ─── Tabby Payment Gateway Environment Variables ──────────────────────────────

TABBY_SANDBOX_MODE=true
# bool | Sandbox mode (testing) when true, Production mode when false

TABBY_SECRET_KEY="sk_test_your_secret_key_here"
# string | Your Tabby secret key from Tabby dashboard
# Prefix: sk_test_ for sandbox | sk_live_ for production

TABBY_MERCHANT_CODE="your_merchant_code_here"
# string | Your merchant code from Tabby dashboard

TABBY_REGION="sa"
# string | Region determines API endpoint
# "sa" = https://api.tabby.sa | "ae" = https://api.tabby.ai | "kw" = https://api.tabby.ai

TABBY_CURRENCY="SAR"
# string (3 chars) | Currency code
# SAR = Saudi Riyal | AED = UAE Dirham | KWD = Kuwaiti Dinar

TABBY_LANGUAGE="ar"
# string | Checkout widget language
# "en" = English | "ar" = Arabic

TABBY_LOGGING=true
# bool | Log all API requests/responses to laravel.log
# true = enabled | false = disabled
```

### 4. Service Provider

[](#4-service-provider)

The package auto-discovers via Laravel's package discovery. If you disable discovery, register manually in `config/app.php`:

```
'providers' => [
    Aghfatehi\Tabby\TabbyServiceProvider::class,
],
```

### 5. Facade (Optional)

[](#5-facade-optional)

```
'aliases' => [
    'Tabby' => Aghfatehi\Tabby\Facades\Tabby::class,
],
```

Usage
-----

[](#usage)

### Quick Start - Frontend Checkout

[](#quick-start---frontend-checkout)

```
use Aghfatehi\Tabby\Facades\Tabby;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redirect;

/**
 * Example controller method showing the full Tabby checkout payload
 * with explicit default values, data types, and field descriptions.
 */
    try {
        // ═══════════════════════════════════════════════════════════════════
        //  1.  PAYMENT DATA
        // ═══════════════════════════════════════════════════════════════════

        $amount   = 500.00;
        // float | Order total (e.g. 500.00)
        // Tabby requires minimum 50 AED or equivalent in other currencies

        $currency = 'SAR';
        // string (3 chars) | Payment currency
        // 'SAR' = Saudi Riyal  |  'AED' = UAE Dirham  |  'KWD' = Kuwaiti Dinar
        // Must match the currency registered in your Tabby account

        $user     = request()->user();
        // ?\Illuminate\Foundation\Auth\User | Authenticated user (may be null)

        // ─── Buyer Information ───────────────────────────────────────────

        $firstName = $user?->name ?? 'Ahmed';
        // string | Buyer's first name - falls back to default if user not logged in

        $lastName  = $user?->name ?? 'Ali';
        // string | Buyer's last name

        $fullName  = trim("$firstName $lastName") ?: 'Ahmed Ali';
        // string | Full name (max 255 chars)

        $email     = $user?->email ?? 'customer@example.com';
        // string | Email address (must be valid for payment notifications)
        // Test: use otp.success@tabby.ai to always succeed

        $phone     = $user?->phone ?? '500000001';
        // string | Phone number WITHOUT country prefix (+)
        // e.g. "500000001" for Saudi Arabia, "500000001" for UAE
        // Test: "500000001" succeeds, "500000000" fails

        $dob       = $user?->dob ?? '1990-01-01';
        // string (YYYY-MM-DD) | Buyer's date of birth (optional, helps approval)

        // ─── Order References ────────────────────────────────────────────

        $orderReferenceId = $request->input('reference_id', 'ORD-' . uniqid());
        // string | Your unique order reference (max 255 chars)
        // Used to link your order with Tabby's payment
        // Pass via POST request to routes: tabby.pay, tabby.callback, tabby.cancel, tabby.failure

        $orderId          = $request->input('order_id', uniqid('ord_'));
        // string | Order ID displayed in Tabby's checkout UI
        // Pass via POST request to routes: tabby.pay

        // ═══════════════════════════════════════════════════════════════════
        //  2.  CHECKOUT PAYLOAD
        // ═══════════════════════════════════════════════════════════════════

        $requestBody = [

            // ─── Payment ────────────────────────────────────────────────────
            'payment' => [

                'amount'      => (string) $amount,
                // string | Total amount as string - "500.00"
                // IMPORTANT: Tabby requires amount as string, NOT float
                // Must be >= 50 AED or equivalent

                'currency'    => $currency,
                // string (3 chars) | Currency - "SAR" | "AED" | "KWD"

                'description' => 'Payment for order #1234',
                // string | Short payment description (max 255 chars)
                // Displayed to the buyer in Tabby's checkout

                // ── Buyer ─────────────────────────────────────────────────────
                'buyer' => [
                    'phone' => $phone,
                    // string | Phone number - "500000001"
                    // WITHOUT country prefix (+966)

                    'email' => $email,
                    // string | Email - "customer@example.com"

                    'name'  => $fullName,
                    // string | Full name - "Ahmed Ali"

                    'dob'   => $dob,
                    // string (YYYY-MM-DD) | Date of birth - "1990-01-01"
                ],

                // ── Buyer History (optional, improves approval rate) ───────
                'buyer_history' => [
                    'registered_since' => $user?->created_at?->format('Y-m-d\TH:i:s\Z')
                                            ?? '2024-01-01T00:00:00Z',
                    // string (ISO8601) | Customer registration date
                    // Older registration = higher approval chance

                    'loyalty_level' => 0,
                    // int | Loyalty tier (0 = new, 1 = regular, 2 = VIP)

                    'wishlist_count' => 0,
                    // int | Number of items in wishlist

                    'is_social_networks_connected' => false,
                    // bool | Does customer have social accounts linked?

                    'is_phone_number_verified' => !empty($phone),
                    // bool | Is phone number verified?

                    'is_email_verified' => !empty($email),
                    // bool | Is email verified?
                ],

                // ── Order ───────────────────────────────────────────────────
                'order' => [
                    'tax_amount'      => '0.00',
                    // string | Tax amount - "0.00" or actual tax

                    'shipping_amount' => '0.00',
                    // string | Shipping cost - "0.00" or actual cost

                    'discount_amount' => '0.00',
                    // string | Discount amount - "0.00" or actual discount

                    'updated_at' => now()->format('Y-m-d\TH:i:s\Z'),
                    // string (ISO8601) | Order last updated timestamp

                    'reference_id' => $orderReferenceId,
                    // string | Your order reference - "ORD-abc123"

                    // ── Order Items ─────────────────────────────────────────
                    'items' => [
                        [
                            'title'           => 'Wireless Headphones',
                            // string | Product name (required)

                            'description'     => 'Bluetooth 5.0',
                            // string | Product description (optional)

                            'quantity'        => 1,
                            // int | Quantity (must be >= 1)

                            'unit_price'      => '500.00',
                            // string | Unit price as string

                            'discount_amount' => '0.00',
                            // string | Discount on this item

                            'reference_id'    => 'SKU-001',
                            // string | SKU or product ID in your system

                            'image_url'       => 'https://example.com/headphones.jpg',
                            // string (URL) | Product image URL (optional)

                            'product_url'     => 'https://example.com/products/1',
                            // string (URL) | Product page URL (optional)

                            'category'        => 'Electronics',
                            // string | Product category (optional)
                        ],
                    ],
                ],

                // ── Shipping Address ────────────────────────────────────────
                'shipping_address' => [
                    'city'    => 'Riyadh',
                    // string | City - e.g. "Riyadh" or "Dubai"

                    'address' => '3764 Al Urubah Rd',
                    // string | Street address

                    'zip'     => '12345',
                    // string | ZIP / postal code
                ],

                // ── Meta ────────────────────────────────────────────────────
                'meta' => [
                    'order_id' => $orderId,
                    // string | Your internal order ID

                    'customer' => (string) ($user?->id ?? 'guest'),
                    // string | Customer ID in your system
                ],
            ],

            // ─── Session Configuration ─────────────────────────────────────
            'lang' => config('tabby.language', 'en'),
            // string | Checkout language - "en" = English | "ar" = Arabic

            'merchant_code' => config('tabby.merchant_code', ''),
            // string | Merchant code in Tabby - "ae" | "sa" | "kw"
            // Must match the code registered in your Tabby account

            // ─── Merchant Callback URLs ───────────────────────────────────
            'merchant_urls' => [
                'success' => route('tabby.callback'),
                // string (URL) | Redirect browser here after successful payment
                // Receives payment_id in query string

                'cancel'  => route('tabby.cancel'),
                // string (URL) | Redirect browser here if user cancels

                'failure' => route('tabby.failure'),
                // string (URL) | Redirect browser here if payment fails
            ],
        ];

        // ═══════════════════════════════════════════════════════════════════
        //  3.  SEND REQUEST  (Submit to Tabby API)
        // ═══════════════════════════════════════════════════════════════════

        if (config('tabby.logging', true)) {
            Log::info('Tabby Checkout Request:', $requestBody);
        }

        $response = Tabby::createCheckout($requestBody);
        // array | API response contains:
        //   ['payment']['id']          => "pay_xxxxxxxx"     (payment ID)
        //   ['id']                     => "uuid-string"      (session ID)
        //   ['configuration']['available_products']['installments'][0]['web_url'] => checkout URL

        if (config('tabby.logging', true)) {
            Log::info('Tabby Checkout Response:', $response);
        }

        // ═══════════════════════════════════════════════════════════════
        //  4.  HANDLE RESPONSE
        // ═══════════════════════════════════════════════════════════════

        if (isset($response['error']) || isset($response['errors'])) {
            // Tabby returned an error - show it to the user
            $error = $response['message']
                  ?? $response['errors'][0]['message']
                  ?? 'Payment initialization failed';
            return back()->withErrors(['error' => $error]);
        }

        $paymentId = $response['payment']['id'] ?? null;
        // string|null | "pay_xxxxxxxx" - Tabby payment ID (store in DB)

        $sessionId = $response['id'] ?? null;
        // string|null | UUID - checkout session ID

        // Extract checkout URL from available products
        $webUrl = $response['configuration']['available_products']['installments'][0]['web_url']
               ?? $response['configuration']['available_products']['pay_by_installments']['web_url']
               ?? null;
        // string|null | URL to redirect buyer to Tabby checkout
        // e.g. "https://checkout.tabby.ai/..."

        // Store in session for callback verification
        session([
            'tabby_payment_id' => $paymentId,
            // string|null | Used in callback to verify payment status
            'tabby_session_id' => $sessionId,
            // string|null | Used in webhook to match the session
        ]);

        if ($webUrl) {
            return Redirect::away($webUrl);
            // Redirect buyer to Tabby checkout page
        }

        return back()->withErrors(['error' => 'No checkout URL returned']);
        // Unexpected: no checkout URL in response

    } catch (\Throwable $e) {
        // API connection error (Network, Timeout, etc.)
        Log::error('Tabby Checkout Exception: ' . $e->getMessage());
        return back()->withErrors(['error' => $e->getMessage()]);
    }
```

### Using Routes

[](#using-routes)

The package registers these routes under the configured prefix (`/tabby` by default):

MethodURINameDescriptionPOST`/tabby/pay``tabby.pay`Initiate checkoutANY`/tabby/callback``tabby.callback`Payment callbackGET`/tabby/cancel``tabby.cancel`Cancel handlerGET`/tabby/failure``tabby.failure`Failure handlerPOST`/tabby/webhook``tabby.webhook`Webhook receiverPOST`/tabby/capture``tabby.capture`Capture paymentPOST`/tabby/refund``tabby.refund`Refund paymentGET`/tabby/payment/{id}``tabby.payment.details`Payment details#### Request Parameters

[](#request-parameters)

RouteParameterTypeRequiredDescription`tabby.pay``amount`numberyesOrder total`reference_id`stringnoYour unique order reference`order_id`stringnoInternal order ID`description`stringnoPayment description`phone`stringnoBuyer phone (without + prefix)`email`stringnoBuyer email`items`arraynoOrder items array`tax_amount`stringnoTax amount`shipping_amount`stringnoShipping amount`discount_amount`stringnoDiscount amount`merchant_urls`objectnoCustom callback URLs (success, cancel, failure)`tabby.callback``payment_id`stringnoTabby payment ID (auto from Tabby redirect)`reference_id`stringnoYour order reference (auto from redirect URL)`tabby.capture``payment_id`stringyesTabby payment ID to capture`amount`numberyesAmount to capture`tabby.refund``payment_id`stringyesTabby payment ID to refund`amount`numberyesAmount to refund**Example - initiating checkout via route:**

```
use Illuminate\Support\Facades\Http;

$response = Http::post('/tabby/pay', [
    'amount'       => 500.00,
    'reference_id' => 'ORD-12345',
    'order_id'     => 'ORD-12345',
    'description'  => 'Payment for order #12345',
    'phone'        => '500000001',
    'email'        => 'otp.success@tabby.ai',
    'merchant_urls' => [
        'success' => route('tabby.callback', ['reference_id' => 100]),
        'cancel'  => route('tabby.cancel', ['reference_id' => 100]),
        'failure' => route('tabby.failure', ['reference_id' => 100]),
    ],
]);
```

### API Methods

[](#api-methods)

```
use Aghfatehi\Tabby\Facades\Tabby;

// Create Checkout Session
$checkout = Tabby::createCheckout($data);

// Retrieve Payment
$payment = Tabby::getPayment('pay_xxxxx');

// Update Payment (e.g., order reference)
$updated = Tabby::updatePayment('pay_xxxxx', [
    'order' => ['reference_id' => 'NEW-ORD-123'],
]);

// Capture Payment (after authorization)
$captured = Tabby::capturePayment('pay_xxxxx', '500.00');

// Refund Payment
$refunded = Tabby::refundPayment('pay_xxxxx', '100.00');

// List Payments with filters
$payments = Tabby::listPayments([
    'created_at__gte' => '2025-03-01',
    'limit' => 20,
]);

// Webhook Management
$webhook = Tabby::webhookRegister('https://example.com/webhook', [
    'title' => 'Authorization',
    'value' => 'Bearer xxx',
]);
$list = Tabby::webhookList();
$detail = Tabby::webhookGet('webhook-id');
Tabby::webhookUpdate('webhook-id', 'https://example.com/webhook-new');
Tabby::webhookDelete('webhook-id');
```

### Amount Formatting

[](#amount-formatting)

```
use Aghfatehi\Tabby\Facades\Tabby;

$formatted = Tabby::formatAmount(100.5); // "100.50"
```

Regions &amp; API Endpoints
---------------------------

[](#regions--api-endpoints)

RegionCodeSandbox URLProduction URLSaudi Arabiasa`https://api.tabby.sa``https://api.tabby.sa`UAEae`https://api.tabby.ai``https://api.tabby.ai`Kuwaitkw`https://api.tabby.ai``https://api.tabby.ai`Webhook Events
--------------

[](#webhook-events)

The webhook endpoint handles these events:

- `payment_authorized` - Payment has been authorized (ready to capture)
- `payment_captured` - Payment has been captured (funds collected)
- `payment_failed` - Payment failed
- `payment_rejected` - Payment was rejected

Customising Routes
------------------

[](#customising-routes)

Publish the config and modify the `routes` section:

```
// config/tabby.php
'routes' => [
    'prefix' => 'payment/tabby',     // Custom prefix
    'middleware' => ['web', 'auth'],   // Custom middleware
],
```

Tabby Testing Credentials
-------------------------

[](#tabby-testing-credentials)

UAE: , phone: +971500000001 KSA: , phone: +966500000001 Kuwait: , phone: +96590000001

otp test: 8888

Test Cards (Sandbox)
--------------------

[](#test-cards-sandbox)

Card TypeNumberExpiryCVVVisa450875001574101907/39100Mastercard512345000000000807/39100AMEX34567890123456407/391000Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

See [CHANGELOG](CHANGELOG.md) for recent changes.

Security
--------

[](#security)

If you discover security issues, please email  instead of using the issue tracker.

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](LICENSE).

Support
-------

[](#support)

- **Issues**: [GitHub Issues](https://github.com/aghfatehi/laravel-tabby/issues)
- **Tabby Docs**:
- **Author**: AL-AGHBARI Fatehi ()

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance94

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~8 days

Total

4

Last Release

31d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/7c0d20683d29aa61fca6b1f9a47a754b2d3e177750f1e8d66975979f2ae8813f?d=identicon)[aghfatehi](/maintainers/aghfatehi)

---

Tags

api-integrationapi-integration-payment-processingbnplbuy-now-pay-latercheckoutecommercefintechgcc-paymentskuwaitlaravellaravel-packagepayment-gatewaypayment-integrationpayment-processingphpsaudi-arabiatabbytabby-payuaewebhookslaravelpaymentgatewaysaudi-arabiainstallmentsbnpltabbykuwaituaepay-in-4

###  Code Quality

TestsPHPUnit

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/aghfatehi-laravel-tabby/health.svg)

```
[![Health](https://phpackages.com/badges/aghfatehi-laravel-tabby/health.svg)](https://phpackages.com/packages/aghfatehi-laravel-tabby)
```

###  Alternatives

[laravel/mcp

Rapidly build MCP servers for your Laravel applications.

77922.3M186](/packages/laravel-mcp)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.3M347](/packages/psalm-plugin-laravel)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M133](/packages/roots-acorn)[api-platform/laravel

API Platform support for Laravel

58174.6k17](/packages/api-platform-laravel)[sebdesign/laravel-viva-payments

A Laravel package for integrating the Viva Payments gateway

4851.0k](/packages/sebdesign-laravel-viva-payments)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
