aghfatehi / laravel-tamara
Tamara Payment Gateway Integration for Laravel - Buy Now Pay Later (BNPL) solution supporting Saudi Arabia, UAE, Kuwait, Bahrain, Qatar, and Oman.
Requires
- php: ^8.1
- illuminate/http: ^10.0|^11.0|^12.0|^13.0
- illuminate/routing: ^10.0|^11.0|^12.0|^13.0
- illuminate/support: ^10.0|^11.0|^12.0|^13.0
- illuminate/validation: ^10.0|^11.0|^12.0|^13.0
Requires (Dev)
- laravel/pint: ^1.0
- orchestra/testbench: ^8.0|^9.0|^10.0|^11.0
- phpunit/phpunit: ^10.0|^11.0
README
A professional Laravel package for integrating Tamara - the leading Buy Now Pay Later (BNPL) payment solution in the Middle East. Supports Saudi Arabia, UAE, Kuwait, Bahrain, Qatar, and Oman.
Features
- ✅ Full Tamara Online Checkout flow
- ✅ Payment Types lookup
- ✅ Create Checkout Sessions
- ✅ Authorise / Capture / Cancel / Refund orders
- ✅ Webhook management (register, list, update, delete)
- ✅ Sandbox & Production environments
- ✅ Multi-currency support (SAR, AED, KWD, BHD, QAR, OMR)
- ✅ Multi-country support (SA, AE, KW, BH, QA, OM)
- ✅ In-store checkout support
- ✅ cURL HTTP client (no Guzzle)
- ✅ Configurable routes prefix & middleware
- ✅ Transaction logging migration
- ✅ Laravel 10, 11, 12 & 13 compatible
- ✅ PHP 8.1+
Requirements
| Laravel | PHP | Package Version |
|---|---|---|
| 10.x | ^8.1 | ^1.0 |
| 11.x | ^8.2 | ^1.0 |
| 12.x | ^8.2 | ^1.0 |
| 13.x | ^8.2 | ^1.0 |
Installation
composer require aghfatehi/laravel-tamara
Configuration
1. Publish Configuration
php artisan vendor:publish --tag=tamara-config
2. Publish Migration (Optional)
php artisan vendor:publish --tag=tamara-migrations php artisan migrate
3. Environment Variables
Add these to your .env file:
TAMARA_SANDBOX_MODE=true TAMARA_API_TOKEN=your-api-token-here TAMARA_COUNTRY_CODE=SA TAMARA_CURRENCY=SAR TAMARA_INSTALMENTS=3 TAMARA_PAYMENT_TYPE=PAY_BY_INSTALMENTS TAMARA_LOCALE=en_US TAMARA_ROUTE_PREFIX=tamara
4. Service Provider
The package auto-discovers via Laravel's package discovery. If you disable discovery, register manually in config/app.php:
'providers' => [ Aghfatehi\Tamara\TamaraServiceProvider::class, ],
5. Facade (Optional)
'aliases' => [ 'Tamara' => Aghfatehi\Tamara\Facades\Tamara::class, ],
Usage
Quick Start - Frontend Checkout
use Aghfatehi\Tamara\Facades\Tamara; // Get available payment types $types = Tamara::getPaymentTypes('SA', 'SAR', 500); // Build checkout request body with example values $requestbody = [ 'total_amount' => [ 'amount' => 500, 'currency' => 'SAR', ], 'shipping_amount' => [ 'amount' => 0, 'currency' => 'SAR', ], 'tax_amount' => [ 'amount' => 0, 'currency' => 'SAR', ], 'order_reference_id' => uniqid('tamara_'), 'order_number' => 'ORD-' . time(), 'items' => [ [ 'name' => 'Order Payment', 'type' => 'Digital', 'reference_id' => '1', 'sku' => 'PAYMENT-001', 'quantity' => 1, 'unit_price' => [ 'amount' => 500, 'currency' => 'SAR', ], 'total_amount' => [ 'amount' => 500, 'currency' => 'SAR', ], ], ], 'consumer' => [ 'email' => 'customer@example.com', 'first_name' => 'Ahmed', 'last_name' => 'Ali', 'phone_number' => '500000000', ], 'country_code' => 'SA', 'description' => 'Payment for order', 'merchant_url' => [ 'success' => route('tamara.callback'), 'failure' => route('tamara.failure'), 'cancel' => route('tamara.cancel'), 'notification' => route('tamara.webhook'), ], 'payment_type' => 'PAY_BY_INSTALMENTS', 'instalments' => 3, 'billing_address' => [ 'city' => 'Riyadh', 'country_code' => 'SA', 'first_name' => 'Ahmed', 'last_name' => 'Ali', 'line1' => 'Default Address', 'phone_number' => '500000000', ], 'shipping_address' => [ 'city' => 'Riyadh', 'country_code' => 'SA', 'first_name' => 'Ahmed', 'last_name' => 'Ali', 'line1' => 'Default Address', 'phone_number' => '500000000', ], 'platform' => 'Laravel', 'is_mobile' => false, 'locale' => 'en_US',//ar_SA for Arabic or en_US for English ]; // Create checkout session $response = Tamara::createCheckout($requestbody); // Redirect customer to Tamara checkout if (isset($response['checkout_url'])) { return redirect()->away($response['checkout_url']); } // Handle errors if (isset($response['errors'])) { $errorMessage = $response['errors'][0]['message'] ?? 'Payment failed'; return back()->with('error', $errorMessage); }
Using Routes
The package registers these routes under the configured prefix (/tamara by default):
| Method | URI | Name | Description |
|---|---|---|---|
| GET | /tamara/payment/types |
tamara.payment.types |
Get eligible payment types |
| POST | /tamara/pay |
tamara.pay |
Initiate checkout |
| ANY | /tamara/callback |
tamara.callback |
Payment callback |
| GET | /tamara/cancel |
tamara.cancel |
Cancel handler |
| GET | /tamara/failure |
tamara.failure |
Failure handler |
| POST | /tamara/webhook |
tamara.webhook |
Webhook receiver |
| POST | /tamara/authorise |
tamara.authorise |
Authorise order |
API Methods
// Payment Types $types = Tamara::getPaymentTypes('SA', 'SAR', 500, '500000000'); // Checkout $checkout = Tamara::createCheckout($data); // Order Management $order = Tamara::getOrder('order-id-here'); $order = Tamara::getOrderByReferenceId('ref-id-here'); // Authorise / Capture / Cancel / Refund $authorised = Tamara::authoriseOrder('order-id'); $captured = Tamara::captureOrder('order-id', $data); $cancelled = Tamara::cancelOrder('order-id', $data); $refunded = Tamara::refundOrder('order-id', 500, 'SAR', 'Refund comment'); // Webhook Management $webhook = Tamara::webhookRegister('https://example.com/webhook', [ 'order_approved', 'order_declined', 'order_authorised', 'order_captured', 'order_refunded', ]); $list = Tamara::webhookList(); $detail = Tamara::webhookGet('webhook-id'); Tamara::webhookDelete('webhook-id'); Tamara::webhookUpdate('webhook-id', 'https://example.com/webhook', [...]);
Customising Routes
Publish the config and modify the routes section:
// config/tamara.php 'routes' => [ 'prefix' => 'payment/tamara', // Custom prefix 'middleware' => ['web', 'auth'], // Custom middleware ],
Handling Webhooks
The webhook endpoint logs all incoming events. Extend the controller or listen to the log to implement your business logic:
// Example webhook payload handling public function webhook(Request $request) { $event = $request->input('event_type'); $orderId = $request->input('order_id'); $status = $request->input('status'); switch ($event) { case 'order_approved': // Mark order as approved break; case 'order_captured': // Fulfill the order break; case 'order_refunded': // Process refund break; } }
Testing
composer test
Changelog
See CHANGELOG for recent changes.
Security
If you discover security issues, please email fathi.a.n2002@gmail.com instead of using the issue tracker.
License
This package is open-sourced software licensed under the MIT license.
Support
- Issues: GitHub Issues
- Tamara Docs: https://docs.tamara.co
- Author: AL-AGHBARI Fatehi (fathi.a.n2002@gmail.com)
Countries & Currencies
| Country | Code | Currency | Code |
|---|---|---|---|
| Saudi Arabia | SA | Riyal | SAR |
| UAE | AE | Dirham | AED |
| Kuwait | KW | Dinar | KWD |
| Bahrain | BH | Dinar | BHD |
| Qatar | QA | Riyal | QAR |
| Oman | OM | Riyal | OMR |