MyFatoorah is a leading payment gateway in the Middle East and North Africa (MENA) region, providing comprehensive payment solutions across 8 countries. This integration supports multiple payment methods including credit/debit cards, bank transfers, e-wallets, and region-specific payment options like KNET (Kuwait), SADAD (Saudi Arabia), and MADA.
| Country | Currency | Code | Primary Payment Methods |
|---|---|---|---|
| Saudi Arabia | Saudi Riyal | SAR | SADAD, MADA, Credit Cards |
| Kuwait | Kuwaiti Dinar | KWD | KNET, KNET Credit, Credit Cards |
| UAE | UAE Dirham | AED | Credit Cards, Debit Cards, Benefit |
| Bahrain | Bahraini Dinar | BHD | Benefit, Credit Cards |
| Oman | Omani Rial | OMR | NAPS, OmanNet |
| Jordan | Jordanian Dinar | JOD | Credit Cards |
| Egypt | Egyptian Pound | EGP | Credit Cards, Mobile Wallets |
| Qatar | Qatari Riyal | QAR | QPay, QCard, Credit Cards |
| Method | Code | Description | Countries |
|---|---|---|---|
| Credit/Debit Card | credit_card | Visa, Mastercard, Amex, UnionPay | All |
| KNET | knet | Kuwait Electronic Payment System | Kuwait |
| SADAD | sadad | Saudi Arabia's bank payment system | Saudi Arabia |
| MADA | mada | Saudi Arabia's debit card system | Saudi Arabia |
| NAPS | naps | Oman's National Payment System | Oman |
| Benefit | benefit | Bahrain's electronic payment | Bahrain |
| QPay | qpay | Qatar's digital wallet system | Qatar |
| STC Pay | stcpay | Saudi Telecom payment service | Saudi Arabia |
| Apple Pay | applepay | Apple digital wallet | All |
| Google Pay | googlepay | Google digital wallet | All |
composer require myfatoorah/laravel-package
Add these variables to your .env file:
# MyFatoorah Configuration
MYFATOORAH_API_KEY=YOUR_API_KEY
MYFATOORAH_TEST_MODE=true
MYFATOORAH_WEBHOOK_URL=https://yourapp.com/payment/myfatoorah/webhook
MYFATOORAH_SUCCESS_URL=https://yourapp.com/payment/myfatoorah/success
MYFATOORAH_ERROR_URL=https://yourapp.com/payment/myfatoorah/error
php artisan vendor:publish --provider="Mdiqbal\LaravelPayments\PaymentsServiceProvider"
// config/payments.php
'gateways' => [
'myfatoorah' => [
'driver' => 'myfatoorah',
'api_key' => env('MYFATOORAH_API_KEY'),
'test_mode' => env('MYFATOORAH_TEST_MODE', true),
'webhook_url' => env('MYFATOORAH_WEBHOOK_URL'),
'success_url' => env('MYFATOORAH_SUCCESS_URL'),
'error_url' => env('MYFATOORAH_ERROR_URL'),
],
],
Once approved:
In your MyFatoorah dashboard:
https://yourapp.com/payment/myfatoorah/webhookuse Mdiqbal\LaravelPayments\Facades\Payment;
use Mdiqbal\LaravelPayments\DTOs\PaymentRequest;
// Initialize MyFatoorah gateway
$payment = Payment::gateway('myfatoorah');
// Create a payment request
$response = $payment->pay(new PaymentRequest(
amount: 100.00,
currency: 'SAR',
orderId: 'ORDER-' . uniqid(),
description: 'Product purchase',
customer: [
'name' => 'Ahmed Mohammed',
'email' => 'ahmed@example.com',
'phone' => '+966501234567',
'country' => 'SA',
],
returnUrl: route('payment.success'),
cancelUrl: route('payment.cancel'),
notifyUrl: route('payment.webhook'),
metadata: [
'language' => 'ar', // or 'en'
'expiry_time' => 1440, // 24 hours in minutes
'user_defined_field' => 'CUSTOM_VALUE',
'items' => [
[
'ItemName' => 'Premium Service',
'Quantity' => 1,
'UnitPrice' => 100.00
]
]
]
));
if ($response->success) {
// Redirect to MyFatoorah payment page
return redirect($response->redirectUrl);
} else {
// Handle error
return back()->with('error', $response->message);
}
$linkResponse = $payment->createPaymentLink([
'amount' => 500.00,
'currency' => 'KWD',
'order_id' => 'LINK-' . time(),
'description' => 'Service payment',
'customer_name' => 'Salem Al-Otaibi',
'customer_email' => 'salem@example.com',
'customer_phone' => '+965511234567',
'customer_reference' => 'REF-' . uniqid(),
'notification_option' => 'All', // Link, SMS, Email
'language' => 'ar',
'expiry_time' => 4320, // 72 hours
'callback_url' => route('payment.webhook'),
'error_url' => route('payment.error'),
'items' => [
[
'ItemName' => 'Consultation Service',
'Quantity' => 1,
'UnitPrice' => 500.00
]
],
]);
if ($linkResponse->success) {
$paymentUrl = $linkResponse->redirectUrl;
// Send payment link via SMS, email, or WhatsApp
return response()->json([
'payment_url' => $paymentUrl,
'invoice_id' => $linkResponse->data['invoice_id']
]);
}
// First, get available payment methods
$paymentMethodsResponse = $payment->getPaymentMethods();
if ($paymentMethodsResponse->success) {
$paymentMethods = $paymentMethodsResponse->data['payment_methods'];
// Find KNET method ID
$knetMethod = collect($paymentMethods)->firstWhere('PaymentMethod', 'knet');
if ($knetMethod) {
$directResponse = $payment->initiatePayment([
'payment_method_id' => $knetMethod['PaymentMethodId'],
'payment_type' => 1,
'amount' => 250.00,
'currency' => 'KWD',
'customer_name' => 'Mohammad Al-Ahmad',
'customer_email' => 'mohammad@example.com',
'customer_phone' => '+965223456789',
'customer_reference' => 'DIR-' . uniqid(),
'redirect_url' => route('payment.redirect'),
'callback_url' => route('payment.webhook'),
'language' => 'ar',
]);
if ($directResponse->success) {
return redirect($directResponse->redirectUrl);
}
}
}
// Check payment status using invoice ID
$invoiceId = '123456789';
$response = $payment->verify(['invoice_id' => $invoiceId]);
if ($response->success) {
echo "Payment Status: " . $response->status;
echo "Invoice ID: " . $response->data['invoice_id'];
echo "Payment ID: " . $response->data['payment_id'];
echo "Amount Paid: " . $response->data['paid_amount'];
echo "Payment Method: " . $response->data['payment_method'];
if ($response->status === 'completed') {
// Update order status
// Send confirmation email
// Process order fulfillment
}
}
// Process a refund
$refundResponse = $payment->refund([
'payment_id' => 'PAYMENT-123456789',
'amount' => 50.00,
'reason' => 'Customer requested partial refund',
'charge_on_customer' => false // Refund charges are borne by merchant
]);
if ($refundResponse->success) {
echo "Refund processed successfully";
echo "Refund ID: " . $refundResponse->data['refund_id'];
echo "Refund Amount: " . $refundResponse->data['refund_amount'];
}
// Saudi Arabia - MADA payment
$saudiPayment = $payment->pay(new PaymentRequest(
amount: 1200.00,
currency: 'SAR',
orderId: 'SA-' . uniqid(),
customer: [
'name' => 'Saeed Al-Harbi',
'email' => 'saeed@example.com',
'phone' => '+966551234567',
],
metadata: [
'payment_method_id' => '2', // MADA method ID
'language' => 'ar',
]
));
// Kuwait - KNET payment
$kuwaitPayment = $payment->pay(new PaymentRequest(
amount: 150.00,
currency: 'KWD',
orderId: 'KW-' . uniqid(),
customer: [
'name' => 'Fahad Al-Mutairi',
'email' => 'fahad@example.com',
'phone' => '+965511234567',
],
metadata: [
'payment_method_id' => '1', // KNET method ID
'language' => 'ar',
]
));
// routes/web.php
Route::post('/payment/myfatoorah/webhook', [MyfatoorahController::class, 'handleWebhook'])
->name('payment.myfatoorah.webhook')
->middleware('myfatoorah.webhook');
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Mdiqbal\LaravelPayments\Facades\Payment;
class MyfatoorahController extends Controller
{
/**
* Handle MyFatoorah webhook
*/
public function handleWebhook(Request $request)
{
$gateway = Payment::gateway('myfatoorah');
// Process webhook
$response = $gateway->processWebhook($request->all());
if ($response->success) {
// Extract webhook data
$webhookData = $response->data;
$eventType = $webhook['webhook_type'];
$status = $response->status;
// Process based on status
switch ($status) {
case 'completed':
$this->handleSuccessfulPayment($webhookData);
break;
case 'pending':
$this->handlePendingPayment($webhookData);
break;
case 'failed':
case 'cancelled':
case 'expired':
$this->handleFailedPayment($webhookData);
break;
case 'refunded':
$this->handleRefund($webhookData);
break;
}
return response('Webhook processed successfully');
}
return response('Webhook processing failed', 400);
}
/**
* Handle successful payment
*/
private function handleSuccessfulPayment(array $data)
{
// Update your database
DB::table('payments')
->where('invoice_id', $data['invoice_id'])
->update([
'status' => 'completed',
'payment_id' => $data['payment_id'],
'payment_method' => $data['payment_method'] ?? null,
'paid_amount' => $data['paid_amount'] ?? 0,
'currency' => $data['invoice_value'] ?? 0,
'transaction_date' => $data['transaction_date'] ?? null,
'customer_reference' => $data['customer_reference'] ?? null,
'paid_at' => now()
]);
// Update order status
DB::table('orders')
->where('id', $data['order_id'] ?? $data['customer_reference'])
->update(['status' => 'paid']);
// Send confirmation email
// Generate receipt
// Trigger fulfillment process
}
/**
* Handle pending payment
*/
private function handlePendingPayment(array $data)
{
DB::table('payments')
->where('invoice_id', $data['invoice_id'])
->update([
'status' => 'pending',
'pending_at' => now()
]);
// Send reminder notification
// Log pending payment
}
/**
* Handle failed payment
*/
private function handleFailedPayment(array $data)
{
DB::table('payments')
->where('invoice_id', $data['invoice_id'])
->update([
'status' => 'failed',
'failure_reason' => $data['status'] ?? 'Payment failed',
'failed_at' => now()
]);
// Notify customer
// Log the failure for review
}
/**
* Handle refund
*/
private function handleRefund(array $data)
{
DB::table('refunds')
->where('payment_id', $data['payment_id'])
->update([
'status' => 'completed',
'processed_at' => now()
]);
// Notify customer
// Update inventory if needed
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class MyfatoorahWebhook
{
// MyFatoorah IP ranges (check documentation for latest IPs)
private $allowedIps = [
'51.15.102.69', // MyFatoorah IP
'51.15.102.71', // MyFatoorah IP
// Add more IPs as provided by MyFatoorah
];
public function handle(Request $request, Closure $next)
{
// Log webhook for debugging
Log::info('MyFatoorah webhook received', [
'ip' => $request->ip(),
'payload' => $request->all()
]);
// Optional: IP filtering
if (!in_array($request->ip(), $this->allowedIps)) {
Log::warning('Unauthorized webhook attempt', [
'ip' => $request->ip()
]);
// Uncomment to enable IP filtering
// abort(403, 'Unauthorized');
}
return $next($request);
}
}
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Mdiqbal\LaravelPayments\Facades\Payment;
class PaymentController extends Controller
{
/**
* Handle successful payment callback
*/
public function handleSuccess(Request $request)
{
$paymentId = $request->get('paymentId');
$invoiceId = $request->get('invoiceId');
// Verify payment status
$gateway = Payment::gateway('myfatoorah');
$response = $gateway->verify(['payment_id' => $paymentId]);
if ($response->success && $response->status === 'completed') {
return view('payment.success', [
'invoice_id' => $response->data['invoice_id'],
'payment_id' => $response->data['payment_id'],
'amount' => $response->data['paid_amount'],
'currency' => $response->data['currency'],
'payment_method' => $response->data['payment_method'],
'transaction_date' => $response->data['transaction_date'],
'customer_name' => $response->data['customer_name'],
]);
}
// Payment not completed yet
return redirect()->route('payment.pending')
->with('invoice_id', $invoiceId);
}
/**
* Show pending payment page
*/
public function showPending(Request $request)
{
$invoiceId = $request->session('invoice_id');
if (!$invoiceId) {
return redirect()->route('home');
}
return view('payment.pending', [
'invoice_id' => $invoiceId,
'check_url' => route('payment.check.status'),
]);
}
/**
* Check payment status (AJAX endpoint)
*/
public function checkStatus(Request $request)
{
$invoiceId = $request->get('invoice_id');
$gateway = Payment::gateway('myfatoorah');
$response = $gateway->verify(['invoice_id' => $invoiceId]);
return response()->json([
'status' => $response->success ? 'success' : 'error',
'data' => $response->data
]);
}
}
MyFatoorah provides a sandbox environment:
MYFATOORAH_TEST_MODE=true
Get test credentials from MyFatoorah:
// Test payment link with email notification
$testLink = $payment->createPaymentLink([
'amount' => 100.00,
'currency' => 'SAR',
'description' => 'Test payment',
'customer_email' => 'test@example.com',
'customer_phone' => '+966501234567',
'notification_option' => 'Email',
'language' => 'en'
]);
// Always validate webhook data structure
if (!isset($data['EventType']) {
Log::error('Invalid webhook structure', ['data' => $data]);
abort(400, 'Invalid webhook');
}
// Optional: Additional security checks
$expectedEventTypes = ['1', '2', '3', '4']; // Payment event types
if (!in_array($data['EventType'], $expectedEventTypes)) {
Log::warning('Unexpected event type', ['event' => $data['EventType']]);
abort(400, 'Unexpected event type');
}
| Code | Description | Solution |
|---|---|---|
| 400 | Bad Request | Check request parameters |
| 401 | Unauthorized | Verify API Key |
| 404 | Not Found | Check endpoint URL |
| 422 | Unprocessable Entity | Check request format |
| 500 | Server Error | Retry with backoff |
| 3001 | Invalid Invoice | Check invoice data |
| 3002 | Duplicate Invoice | Use unique IDs |
| 3003 | Invalid Amount | Check amount format |
try {
$response = $payment->pay($paymentRequest);
if (!$response->success) {
// Log error details
Log::error('MyFatoorah payment failed', [
'error_code' => $response->errorCode,
'message' => $response->message,
'order_id' => $paymentRequest->orderId
]);
// Show user-friendly message
$userMessage = $this->getUserFriendlyErrorMessage($response->errorCode);
return back()->with('error', $userMessage);
}
} catch (\Exception $e) {
Log::error('MyFatoorah gateway error', [
'error' => $e->getMessage()
]);
return back()->with('error', 'Payment service temporarily unavailable.');
}
private function getUserFriendlyErrorMessage(string $errorCode): string
{
$errorMessages = [
'3001' => 'Invalid invoice data. Please check the format.',
'3002' => 'Duplicate invoice. Please use a unique reference.',
'3003' => 'Invalid amount format. Please check the amount.',
'3004' => 'Invalid currency. Please use supported currencies.',
'3005' => 'Payment method not available. Please try another option.',
];
return $errorMessages[$errorCode] ?? 'Payment failed. Please try again.';
}
// Cache payment methods information
$paymentMethods = Cache::remember('myfatoorah_payment_methods', 3600, function () {
$gateway = Payment::gateway('myfatoorah');
$response = $gateway->getPaymentMethods();
return $response->success ? $response->data['payment_methods'] : [];
});
// Use CDN for static assets
<script src="https://portal.myfatoorah.com/portal/v1/js/payment-methods.js"></script>
// Set language based on customer preference or country
$language = $request->metadata['language'] ?? 'en';
// Adjust currency formatting based on locale
if ($request->currency === 'SAR') {
$formattedAmount = number_format($amount, 2, '.', ',');
} else {
$formattedAmount = number_format($amount, 2, '.', ',');
}
MyFatoorah supports multiple languages:
// English (default)
'language' => 'en'
// Arabic
'language' => 'ar'
Payment Link Not Created
Webhook Not Received
**Payment Method Not...
How can I help you explore Laravel packages today?