alsharie/jawali-payment
Laravel client for the Jawali payment gateway. Provides simple methods for ecommerce inquiry and cash out, with automatic token handling, configurable base URL/SSL, retries/timeouts, optional logging, and structured API responses via Laravel config/env.
Installation
composer require alsharie/jawali-payment
Publish the config file:
php artisan vendor:publish --provider="Alsharie\JawaliPayment\JawaliPaymentServiceProvider" --tag="config"
Configuration
Edit .env with your Jawali API credentials:
JAWALI_API_KEY=your_api_key_here
JAWALI_API_SECRET=your_api_secret_here
JAWALI_ENVIRONMENT=sandbox # or 'live'
First Use Case: Create a Payment Intent
use Alsharie\JawaliPayment\Facades\JawaliPayment;
$intent = JawaliPayment::createPaymentIntent([
'amount' => 100.00, // in SAR
'currency' => 'SAR',
'description' => 'Order #12345',
'metadata' => ['order_id' => '12345'],
]);
return redirect()->to($intent->payment_url);
config/jawali-payment.php (API endpoints, default settings).app/Facades/JawaliPayment.php (if extended).vendor/alsharie/jawali-payment/src/JawaliPaymentServiceProvider.php (for custom bindings).$intent = JawaliPayment::createPaymentIntent($request->all());
routes/web.php):
Route::post('/jawali-webhook', [PaymentWebhookController::class, 'handle']);
// PaymentWebhookController.php
public function handle(Request $request) {
$event = JawaliPayment::verifyWebhook($request->all());
// Process event (e.g., update order status)
}
$subscription = JawaliPayment::createSubscription([
'customer_id' => $customer->jawali_id,
'items' => [['price_id' => 'price_123']],
]);
JawaliPayment::cancelSubscription($subscription->id);
JawaliPayment::createRefund($payment->id, ['amount' => 50.00]);
$dispute = JawaliPayment::createDispute($charge->id, ['amount' => 100.00, 'reason' => 'fraudulent']);
$customer = JawaliPayment::createCustomer([
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => '+966551234567',
]);
$order->customer()->attach($customer->id);
event(new PaymentSucceeded($intent->id, $intent->amount));
Queue::push(new ProcessJawaliWebhook($event));
// app/Services/PaymentService.php
public function processPayment(Order $order) {
$intent = JawaliPayment::createPaymentIntent($order->toJawaliArray());
return $intent;
}
sandbox environment for testing:
JAWALI_ENVIRONMENT=sandbox
JawaliPayment::shouldReceive('createPaymentIntent')->andReturn($mockIntent);
Enable debug logging in config/jawali-payment.php:
'debug' => env('JAWALI_DEBUG', false),
View logs in storage/logs/laravel.log.
Webhook Verification
$event = JawaliPayment::verifyWebhook($request->all(), $request->get('signature'));
JAWALI_WEBHOOK_SECRET in .env for local testing.Currency and Amount
100.00 SAR = 10000 halalas).'amount' => $order->total * 100,
Idempotency Keys
JawaliPayment::createPaymentIntent($data, ['idempotency_key' => uniqid()]);
Rate Limits
$customer = Cache::remember("jawali_customer_{$user->id}", now()->addHours(1), function() use ($user) {
return JawaliPayment::createCustomer($user->toJawaliArray());
});
Error Handling
402 for insufficient funds). Handle gracefully:
try {
$intent = JawaliPayment::createPaymentIntent($data);
} catch (\Alsharie\JawaliPayment\Exceptions\JawaliException $e) {
return back()->withError($e->getMessage());
}
Enable Debug Mode
Set JAWALI_DEBUG=true in .env to log raw API responses.
Test with Sandbox Use Jawali’s sandbox tester to simulate payments.
Check Headers
Ensure Authorization and Content-Type headers are set:
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . config('jawali.api_key'),
'Content-Type' => 'application/json',
])->post('https://api.jawali.com/v1/payment_intents', $data);
Common Errors
invalid_request_error: Validate required fields (e.g., currency, amount).authentication_error: Verify JAWALI_API_KEY and JAWALI_API_SECRET.resource_missing: Ensure the customer/subscription exists before acting on it.Custom Facade Extend the facade to add domain-specific methods:
// app/Facades/ExtendedJawaliPayment.php
class ExtendedJawaliPayment extends JawaliPayment {
public function createOrderPayment(Order $order) {
return parent::createPaymentIntent($order->toJawaliArray());
}
}
Middleware for API Calls Add middleware to log or transform requests:
// app/Http/Middleware/JawaliRequestMiddleware.php
public function handle($request, Closure $next) {
if ($request->routeIs('jawali.*')) {
// Modify request data
}
return $next($request);
}
Custom Webhook Handlers Route webhooks to specific handlers:
// routes/web.php
Route::post('/jawali-webhook', function (Request $request) {
$event = JawaliPayment::verifyWebhook($request->all());
app()->call([\App\Handlers\WebhookHandlers::class, $event->type], ['event' => $event]);
});
Local Overrides Override API endpoints in config:
'endpoints' => [
'api' => env('JAWALI_API_URL', 'https://api.jawali.com'),
'webhook' => env('JAWALI_WEBHOOK_URL', 'https://your-app.com/jawali-webhook'),
],
Testing Helpers
Add test helpers to app/Helpers/JawaliTestHelper.php:
function mockJawaliResponse($status, $data = []) {
JawaliPayment::shouldReceive('createPaymentIntent')
->andReturn((object) ['id' => 'pi_12
How can I help you explore Laravel packages today?