el3wdy / skipcash-laravel
Production-ready Laravel package for SkipCash payment integration with first-class developer experience
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/el3wdy/skipcash-laravel
Requires
- php: ^8.2
- illuminate/contracts: ^10.0|^11.0|^12.0
- illuminate/database: ^10.0|^11.0|^12.0
- illuminate/http: ^10.0|^11.0|^12.0
- illuminate/queue: ^10.0|^11.0|^12.0
- illuminate/support: ^10.0|^11.0|^12.0
- illuminate/validation: ^10.0|^11.0|^12.0
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- orchestra/testbench: ^8.0|^9.0|^10.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpunit/phpunit: ^10.0|^11.0
This package is not auto-updated.
Last update: 2026-01-07 21:58:21 UTC
README
A production-ready Laravel package for SkipCash payment integration with first-class developer experience. This package provides a clean API client, secure webhook handling, events, and comprehensive test coverage for Laravel 10/11/12 (PHP 8.2+).
Features
- ๐ Clean API: Fluent, type-safe SDK for payment operations
- ๐ Security First: HMAC-SHA256 signature verification for all requests
- ๐ฏ Laravel Events: Automatic event dispatching for payment status changes
- ๐ Webhook Handling: Secure, idempotent webhook processing with queue support
- ๐ Local Storage: Optional payment records storage with Eloquent model
- ๐งช Fully Tested: Comprehensive test suite with 100% coverage
- ๐ Type Safe: Full PHP 8.2+ type declarations and PHPDoc annotations
- โก Production Ready: Built-in retries, timeouts, and error handling
Installation
You can install the package via composer:
composer require el3wdy/skipcash-laravel
Publish the configuration file:
php artisan vendor:publish --tag="skipcash-config"
Optionally, publish the migrations:
php artisan vendor:publish --tag="skipcash-migrations"
php artisan migrate
Configuration
Add the following environment variables to your .env file:
# SkipCash Environment (sandbox or production) SKIPCASH_ENV=sandbox # API Credentials (from SkipCash Merchant Portal > Online Payments) SKIPCASH_KEY_ID=your-key-id SKIPCASH_KEY_SECRET=your-key-secret SKIPCASH_WEBHOOK_KEY=your-webhook-key # Optional: Webhook Configuration SKIPCASH_WEBHOOK_PATH=/skipcash/webhook SKIPCASH_WEBHOOK_QUEUE=default # Optional: HTTP Client Settings SKIPCASH_TIMEOUT=10 SKIPCASH_RETRIES=3 # Optional: Local Payment Storage SKIPCASH_STORE_PAYMENTS=true
Getting Your API Credentials
- Log in to your SkipCash Merchant Portal
- Navigate to Online Payments section
- Copy your
Key IDandKey Secretfor API authentication - Copy your
Webhook Keyfor webhook signature verification - For production, ensure you're using production credentials and set
SKIPCASH_ENV=production
Usage
Creating a Payment
use SkipCash; // In your controller public function createPayment(Request $request) { $payment = SkipCash::createPayment([ // Required fields 'Amount' => number_format($order->total, 2, '.', ''), 'FirstName' => $user->first_name, 'LastName' => $user->last_name, 'Phone' => $user->phone, // with country code (+965...) 'Email' => $user->email, // Optional fields 'Street' => $user->address, 'City' => $user->city, 'Country' => 'KW', 'TransactionId' => $order->id, // Your internal order ID 'Custom1' => 'any-custom-data', ]); // Redirect user to SkipCash payment page return redirect()->away($payment->payUrl); }
Retrieving Payment Details
$payment = SkipCash::getPayment('pay_123456789'); echo $payment->paymentId; // 'pay_123456789' echo $payment->amount; // '100.00' echo $payment->statusId; // 2 (Paid) echo $payment->getStatusName(); // 'Paid' // Check payment status if ($payment->isPaid()) { // Payment successful } elseif ($payment->isFailed()) { // Payment failed } elseif ($payment->isPending()) { // Payment pending }
Processing Refunds
$refund = SkipCash::refund( paymentId: 'pay_123456789', amount: '50.00', reason: 'Customer request' );
Webhook Handling
The package automatically handles SkipCash webhooks and dispatches Laravel events based on payment status changes.
Webhook Configuration
-
In your SkipCash Merchant Portal, set your webhook URL to:
https://your-domain.com/skipcash/webhook -
The package automatically verifies webhook signatures and processes them asynchronously via Laravel queues.
Payment Status Events
The package dispatches the following events based on StatusId:
| StatusId | Event | Description |
|---|---|---|
| 1 | PaymentPending |
Payment is pending |
| 2 | PaymentPaid |
Payment completed successfully |
| 3 | PaymentCanceled |
Payment was canceled |
| 4, 5 | PaymentFailed |
Payment failed |
| 6 | PaymentRefunded |
Payment was refunded |
| 7 | PaymentRefundPending |
Refund is pending |
| 8 | PaymentRefundFailed |
Refund failed |
Listening to Payment Events
Create event listeners to handle payment status changes:
// In EventServiceProvider.php use El3wdy\Skipcash\Events\PaymentPaid; use El3wdy\Skipcash\Events\PaymentFailed; protected $listen = [ PaymentPaid::class => [ UpdateOrderStatus::class, SendPaymentConfirmation::class, ], PaymentFailed::class => [ HandleFailedPayment::class, ], ];
Example listener:
<?php namespace App\Listeners; use El3wdy\Skipcash\Events\PaymentPaid; use App\Models\Order; class UpdateOrderStatus { public function handle(PaymentPaid $event): void { if ($event->transactionId) { $order = Order::find($event->transactionId); $order?->markAsPaid(); } } }
Webhook Security
- All webhooks are automatically verified using HMAC-SHA256 signatures
- Invalid signatures are rejected with 401 Unauthorized
- Duplicate webhooks are handled idempotently using cache locks
- Processing is deferred to queues for fast response times (<10s)
Webhook Retry Behavior
SkipCash retries failed webhooks with the following schedule:
- Immediate retry
- +1 hour retry
- +1 day retry
The package handles out-of-order delivery and duplicate events automatically.
Local Payment Storage
When SKIPCASH_STORE_PAYMENTS=true (default), the package stores payment records locally:
use El3wdy\Skipcash\Models\SkipcashPayment; // Find payments $payment = SkipcashPayment::findByPaymentId('pay_123456789'); $payment = SkipcashPayment::findByTransactionId('ORDER-123'); // Query payments $paidPayments = SkipcashPayment::paid()->get(); $failedPayments = SkipcashPayment::failed()->get(); $recentPayments = SkipcashPayment::where('created_at', '>', now()->subDays(7))->get(); // Access payment data echo $payment->payment_id; // 'pay_123456789' echo $payment->amount; // 100.00 echo $payment->status_name; // 'Paid' echo $payment->raw_payload; // Full webhook payload
StatusId Reference
| StatusId | Status Name | Description |
|---|---|---|
| 0 | New | Payment created but not processed |
| 1 | Pending | Payment is being processed |
| 2 | Paid | Payment completed successfully |
| 3 | Canceled | Payment was canceled by user |
| 4 | Failed | Payment failed (generic) |
| 5 | Failed | Payment failed (specific) |
| 6 | Refunded | Payment was refunded |
| 7 | Pending Refund | Refund is being processed |
| 8 | Refund Failed | Refund processing failed |
Testing
Webhook Simulator
For testing webhooks, you can use the SkipCash webhook simulator with these parameters:
{
"PaymentId": "pay_test_123456789",
"Amount": "100.00",
"StatusId": 2,
"TransactionId": "ORDER-123",
"Custom1": "test-data",
"VisaId": "visa_test_123456789"
}
Unit Testing
The package includes comprehensive tests. Run them with:
composer test
Testing in Your Application
Use the provided test helpers:
use El3wdy\Skipcash\Tests\TestCase; use Illuminate\Support\Facades\Http; class PaymentTest extends TestCase { /** @test */ public function it_creates_payment_successfully() { Http::fake([ 'skipcashtest.azurewebsites.net/*' => Http::response([ 'PaymentId' => 'pay_123456789', 'PayUrl' => 'https://pay.skipcash.app/pay/123456789', ], 200) ]); $response = SkipCash::createPayment([ 'Amount' => '100.00', 'FirstName' => 'John', 'LastName' => 'Doe', 'Phone' => '+96550000000', 'Email' => 'john@example.com', ]); $this->assertEquals('pay_123456789', $response->paymentId); } }
API Reference
SkipCash Facade Methods
// Create a payment SkipCash::createPayment(array $paymentData): PaymentResponse // Get payment details SkipCash::getPayment(string $paymentId): PaymentDetails // Process refund SkipCash::refund(string $paymentId, string $amount, ?string $reason = null): array // Get underlying HTTP client SkipCash::getClient(): SkipCashClient
Data Objects
PaymentResponse
$response->paymentId; // string $response->payUrl; // string $response->visaTransactionId; // ?string $response->rawResponse; // array
PaymentDetails
$details->paymentId; // string $details->amount; // string $details->statusId; // int $details->transactionId; // ?string $details->custom1; // ?string $details->visaId; // ?string $details->firstName; // ?string $details->lastName; // ?string $details->email; // ?string $details->phone; // ?string $details->rawResponse; // array // Helper methods $details->getStatusName(); // string $details->isPaid(); // bool $details->isFailed(); // bool $details->isPending(); // bool
Environment URLs
The package automatically uses the correct API endpoints based on your environment:
- Sandbox:
https://skipcashtest.azurewebsites.net/api/v1/ - Production:
https://api.skipcash.app/api/v1/
Security Considerations
- Never log or expose your
SKIPCASH_KEY_SECRETorSKIPCASH_WEBHOOK_KEY - Always use HTTPS in production
- Webhook signatures are verified automatically
- All amounts are validated and normalized
- Field ordering for signatures is strictly enforced per SkipCash documentation
Error Handling
The package throws SkipCashException for API errors:
use El3wdy\Skipcash\Exceptions\SkipCashException; try { $payment = SkipCash::createPayment($data); } catch (SkipCashException $e) { Log::error('SkipCash payment failed: ' . $e->getMessage()); // Handle error appropriately }
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.