nikba/laravel-maib

Laravel 12 integration for the maib e-Commerce API — all payment types, token management, and webhook handling.

Maintainers

Package info

github.com/Nikba-Creative-Studio/Laravel-Maib

pkg:composer/nikba/laravel-maib

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-15 09:23 UTC

This package is auto-updated.

Last update: 2026-03-15 14:10:08 UTC


README

Nikba Creative Studio

Latest Version on Packagist License

A Laravel 12 package for the maib e-Commerce API — full coverage of all payment types, automatic token management, and HMAC-SHA256 callback webhook handling.

API documentation: https://docs.maibmerchants.md/e-commerce

Features

  • Direct payment (one-step charge)
  • Two-step payment (hold → capture or cancel)
  • Recurring payments (register card + server-side execute)
  • One-click payments (register card + redirect execute)
  • Payment refund (partial or full)
  • Payment information query
  • Saved card deletion
  • Callback webhook handling with HMAC-SHA256 signature validation
  • Laravel Events dispatched on successful/failed callbacks
  • Automatic Bearer token generation, caching, and refresh
  • Full PHPUnit test suite

Requirements

Version
PHP ^8.2
Laravel ^12.0

Installation

composer require nikba/laravel-maib

Publish the configuration

php artisan vendor:publish --tag=maib-config

Environment variables

Add the following to your .env file:

MAIB_PROJECT_ID=your-project-id
MAIB_PROJECT_SECRET=your-project-secret
MAIB_SIGNATURE_KEY=your-signature-key
MAIB_ENV=sandbox
MAIB_CALLBACK_ROUTE=/maib/callback

Credentials are available in maibmerchants.md under your project settings.

Configuration

After publishing, edit config/maib.php:

return [
    'project_id'     => env('MAIB_PROJECT_ID'),
    'project_secret' => env('MAIB_PROJECT_SECRET'),
    'signature_key'  => env('MAIB_SIGNATURE_KEY'),
    'environment'    => env('MAIB_ENV', 'production'),
    'base_url'       => 'https://api.maibmerchants.md/v1',
    'callback_route' => env('MAIB_CALLBACK_ROUTE', '/maib/callback'),
    'cache_driver'   => env('MAIB_CACHE_DRIVER', null),
    'cache_prefix'   => 'maib_token',
];

Usage

Direct Payment

use Nikba\LaravelMaib\Facades\Maib;
use Nikba\LaravelMaib\Dto\Requests\DirectPaymentRequest;
use Nikba\LaravelMaib\Dto\PaymentItem;
use Nikba\LaravelMaib\Enums\Currency;
use Nikba\LaravelMaib\Enums\Language;

$response = Maib::directPayment(
    new DirectPaymentRequest(
        amount:      99.99,
        currency:    Currency::MDL,
        clientIp:    $request->ip(),
        language:    Language::RO,
        orderId:     'ORDER-001',
        description: 'Order #001',
        callbackUrl: route('maib.callback'),
        okUrl:       route('payment.success'),
        failUrl:     route('payment.fail'),
        items: [
            new PaymentItem(id: '1', name: 'Product A', price: 99.99, quantity: 1),
        ],
    )
);

return redirect($response->payUrl);

Two-Step Payment (Hold → Capture)

use Nikba\LaravelMaib\Dto\Requests\CapturePaymentRequest;
use Nikba\LaravelMaib\Dto\Requests\HoldPaymentRequest;

// Step 1: Hold
$hold = Maib::hold(new HoldPaymentRequest(
    amount:   99.99,
    currency: Currency::MDL,
    clientIp: $request->ip(),
    language: Language::RO,
));

return redirect($hold->payUrl);

// Step 2: Capture (after callback confirms hold)
$capture = Maib::capture(new CapturePaymentRequest(
    payId:         $payId,
    confirmAmount: 99.99, // optional — omit to capture full hold amount
));

Recurring Payments

use Nikba\LaravelMaib\Dto\Requests\ExecuteRecurringRequest;
use Nikba\LaravelMaib\Dto\Requests\SaveCardRecurringRequest;

// Registration (once per customer — redirect to 3DS checkout)
$save = Maib::savecardRecurring(new SaveCardRecurringRequest(
    billerExpiry: '1228',
    clientIp:     $request->ip(),
    currency:     Currency::MDL,
    language:     Language::RO,
    email:        'user@example.com',
));

return redirect($save->payUrl);
// Callback will return billerId — store it for the customer.

// Server-side execution (no customer redirect)
$response = Maib::executeRecurring(new ExecuteRecurringRequest(
    billerId: $user->maib_biller_id,
    amount:   29.99,
    currency: Currency::MDL,
    orderId:  'SUBSCRIPTION-' . now()->format('Y-m'),
));

if ($response->status === \Nikba\LaravelMaib\Enums\TransactionStatus::OK) {
    // subscription renewed
}

One-Click Payments

use Nikba\LaravelMaib\Dto\Requests\ExecuteOneclickRequest;
use Nikba\LaravelMaib\Dto\Requests\SaveCardOneclickRequest;

// Registration
$save = Maib::savecardOneclick(new SaveCardOneclickRequest(
    billerExpiry: '1228',
    clientIp:     $request->ip(),
    currency:     Currency::MDL,
    language:     Language::RO,
    email:        'user@example.com',
));

return redirect($save->payUrl);

// Execution (redirects customer to checkout for 3DS confirmation)
$response = Maib::executeOneclick(new ExecuteOneclickRequest(
    billerId:  $user->maib_biller_id,
    amount:    49.99,
    currency:  Currency::MDL,
    clientIp:  $request->ip(),
    language:  Language::RO,
));

return redirect($response->payUrl);

Refund

use Nikba\LaravelMaib\Dto\Requests\RefundRequest;

$response = Maib::refund(new RefundRequest(
    payId:        $payId,
    refundAmount: 30.00, // optional — omit to refund the full amount
));

Payment Info

$info = Maib::payInfo($payId);

echo $info->status->value;   // 'OK', 'FAILED', etc.
echo $info->cardNumber;

Delete Saved Card

$response = Maib::deleteCard($billerId);

Handling Callbacks

The package automatically registers the callback route at MAIB_CALLBACK_ROUTE (default: /maib/callback). This route is excluded from CSRF middleware.

Register this URL in your maibmerchants.md project settings.

Allowed callback IPs (optional firewall rule): 91.250.245.70, 91.250.245.71, 91.250.245.142

Listening for Events

// In App\Providers\EventServiceProvider (or using #[AsEventListener])
use Nikba\LaravelMaib\Events\MaibPaymentFailed;
use Nikba\LaravelMaib\Events\MaibPaymentReceived;

Event::listen(MaibPaymentReceived::class, function (MaibPaymentReceived $event) {
    $payload = $event->payload;

    Order::where('maib_pay_id', $payload->payId)
        ->update([
            'status'      => 'paid',
            'rrn'         => $payload->rrn,
            'approval'    => $payload->approval,
            'card_number' => $payload->cardNumber,
        ]);
});

Event::listen(MaibPaymentFailed::class, function (MaibPaymentFailed $event) {
    Order::where('maib_pay_id', $event->payload->payId)
        ->update(['status' => 'failed']);
});

Important: Always return HTTP 200 from your listener logic — the package's callback handler already does this. maib retries the callback at increasing intervals (10, 60, 300, 600, 3600, 43200, 86400 seconds) if it does not receive a 200 response. Implement idempotency in your listeners.

Testing

composer test

Author

Nicolai Bargan
Nikba Creative Studio
office@nikba.com

License

The MIT License (MIT). See LICENSE for details.