Download the PHP package mlquarizm/payment-gateway without Composer
On this page you can find all versions of the php package mlquarizm/payment-gateway. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download mlquarizm/payment-gateway
More information about mlquarizm/payment-gateway
Files in mlquarizm/payment-gateway
Package payment-gateway
Short Description Laravel Payment Gateway Package for Tabby and Tamara
License MIT
Homepage https://github.com/your-org/ml-payment-gateway
Informations about the package payment-gateway
ML Payment Gateway Package
Laravel package for integrating Tabby and Tamara payment gateways.
📋 For detailed architecture and development plan, see PLAN.md
Installation
Via Composer (if published to Packagist)
Via Git Repository (Private Package)
Add to your composer.json:
Then run:
Via Local Path (Development)
Add to your composer.json:
Then run:
Configuration
Publish the configuration files:
Run migrations:
CSRF Configuration
Since payment callbacks and webhooks come from external sources, you need to exclude them from CSRF verification.
Add the following routes to your app/Http/Middleware/VerifyCsrfToken.php:
Environment Variables
Add to your .env file:
Callback vs redirect URLs
- TABBY_SUCCESS_URL / TAMARA_SUCCESS_URL (and failure/cancel): Must point to this project’s callback route so the package can process the payment. Use the package route, e.g.
https://yourdomain.com/payment/callback/tabby(same idea for Tamara). The gateway redirects the user here after payment; the package then processes the result and redirects the user again. - TABBYREDIRECT / TAMARAREDIRECT: Where to send the user after the package has processed the callback (e.g. your
payment-status/{status}/{language}Blade page). The callback always redirects (never returns JSON); if these are not set, it usesPAYMENT_REDIRECT_FALLBACK_URLor the app root.
Configuration Files
The package includes three configuration files that you can customize after publishing:
1. config/payment-gateway.php (Main Configuration)
This is the main configuration file for the package:
Configuration Options:
-
default_gateway: The default payment gateway to use when not explicitly specified. Options:'tabby'or'tamara'. -
redirect_fallback_url: When a gateway-specificredirect_success_url/redirect_error_url/redirect_cancel_urlis not set, the callback redirects here with?status=...&gateway=.... Leave empty to fall back to the app root. -
redirect_after_status_url: URL the user is sent to after the package status Blade (5s redirect). Use placeholder{order_id}; replaced by payable id (e.g. order id). Example:https://yourdomain.com/orders/{order_id}. Set in.envasPAYMENT_REDIRECT_AFTER_STATUS_URL. -
redirect_after_status_fallback_url: Whenredirect_after_status_urlis empty (or when order id is missing), the Blade redirects here. Use a public URL (e.g. dashboard or home). Avoid auth/login routes. SetPAYMENT_REDIRECT_AFTER_STATUS_FALLBACK_URLin.env. transaction: Configuration for payment transactions:table: Database table name for storing payment transactions.polymorphic: Enable polymorphic relationships to link transactions to different models (Order, Invoice, etc.).
2. config/tabby.php (Tabby Gateway Configuration)
Configuration specific to Tabby payment gateway:
Configuration Options:
-
sandbox_mode: Set totruefor testing,falsefor production. When enabled, uses Tabby's sandbox environment. -
API Credentials:
secret_key: Your Tabby secret key (obtained from Tabby dashboard).public_key: Your Tabby public key.merchant_code: Your merchant code.
-
Callback URLs: URLs where Tabby sends payment status updates:
success_url: Called when payment succeeds.failure_url: Called when payment fails.cancel_url: Called when user cancels payment.
-
Redirect URLs: URLs where users are redirected after processing the callback:
redirect_success_url: User redirect after successful payment.redirect_error_url: User redirect after failed payment.redirect_cancel_url: User redirect after cancelled payment.
currency: Currency code (ISO 4217). Default:'SAR'(Saudi Riyal).
3. config/tamara.php (Tamara Gateway Configuration)
Configuration specific to Tamara payment gateway:
Configuration Options:
-
sandbox_mode: Set totruefor testing,falsefor production. When enabled, uses Tamara's sandbox environment. -
API Credentials:
api_token: Your Tamara API token (obtained from Tamara dashboard).notification_token: Token for verifying notifications.webhook_token: Token for verifying webhook requests.public_key: Your Tamara public key.
-
Callback URLs: URLs where Tamara sends payment status updates:
success_url: Called when payment succeeds.failure_url: Called when payment fails.cancel_url: Called when user cancels payment.
-
Redirect URLs: URLs where users are redirected after processing the callback:
redirect_success_url: User redirect after successful payment.redirect_error_url: User redirect after failed payment.redirect_cancel_url: User redirect after cancelled payment.
-
Payment Options:
default_payment_type: Default payment type. Options:'PAY_BY_INSTALMENTS','PAY_LATER', etc.default_instalments: Default number of instalments (typically 3, 6, or 12).
- Localization:
currency: Currency code (ISO 4217). Default:'SAR'.country_code: Country code (ISO 3166-1 alpha-2). Default:'SA'(Saudi Arabia).locale: Locale code. Default:'ar_SA'(Arabic - Saudi Arabia).
Usage
Basic Usage with Tabby
Important: You must call PaymentGateway::recordTransaction(...) (or create a row with the package’s PaymentTransaction model) after initiatePayment and before redirecting the user to the gateway. Otherwise the callback/webhook will not find a transaction to update.
Handling Tabby Pre-scoring Rejection
Tabby performs a Background Pre-scoring check when you call initiatePayment(). If the buyer is not eligible (e.g. credit risk, amount limits), Tabby rejects the session immediately — before the user is ever redirected to Tabby’s checkout page.
You must check $paymentInfo[‘success’] before redirecting. If you skip this check and blindly call redirect($paymentInfo[‘url’]), the URL will be null and the user will see a broken page instead of a helpful rejection message.
Response on rejection:
Rejection reasons:
| Reason | English Message | Arabic Message |
|---|---|---|
not_available |
Sorry, Tabby is unable to approve this purchase. Please use an alternative payment method for your order. | ... تابي غير قادرة على الموافقة |
order_amount_too_high |
This purchase is above your current spending limit with Tabby, try a smaller cart or use another payment method. | ... قيمة الطلب تفوق الحد الأقصى |
order_amount_too_low |
The purchase amount is below the minimum amount required to use Tabby, try adding more items or use another payment method. | ... قيمة الطلب أقل من الحد الأدنى |
The message language is determined automatically based on app()->getLocale().
Testing pre-scoring rejection: See Tabby Testing Guidelines - Background Pre-scoring Reject for test credentials that trigger rejection.
Callback flow: default is package Blade (never JSON)
The package callback (GET or POST to payment/callback/{gateway}) uses the same “pay or not” logic as the webhook: it finds the transaction by track_id/payment_id, updates status, and fires events. The only difference is the response:
- Default: Callback redirects to the package status Blade at
payment-gateway/status/{status}(public, no auth). After 5s the Blade redirects to the URL from env; setPAYMENT_REDIRECT_AFTER_STATUS_FALLBACK_URLto a public URL (e.g. dashboard) so users are not sent to login. If gateway redirect URLs are set and you need custom behaviour, the callback can use those instead (with?status=...&gateway=...). This matches the usual “return from gateway → process → show success/error/cancel page” flow. - The callback always redirects (never returns JSON). If gateway-specific redirect URLs are not set, it uses
payment-gateway.redirect_fallback_url, or the app root with?status=...&gateway=....
The webhook endpoint is unchanged (returns 200, no redirect).
Using Builder Pattern
Important:
buyerHistory()andorderHistory()are required for Tabby. Tabby uses this data for pre-scoring and risk assessment. If you don't provide them, the builder will throw anInvalidArgumentException. Pass an empty array[]toorderHistory()if the buyer has no previous orders.Note:
shippingAddress()is optional.buyer()requires onlyname—phoneare optional (passnullor empty string to omit them from the Tabby request).
Full Example
Using OrderHistoryDTO
Instead of raw arrays, you can use OrderHistoryDTO instances for type safety:
Note:
orderHistory()accepts both raw arrays andOrderHistoryDTO[]. Raw arrays are sent to Tabby as-is, whileOrderHistoryDTOinstances are serialized by the package.
Minimal Example (no shipping address, no email/phone, new buyer with no order history)
Multiple Items
You can add multiple items in two ways:
Option 1: Using item() method multiple times
Option 2: Using items() method with array
Option 3: Using items() with array of arrays
Using Tamara
Multiple Items
You can add multiple items using the same methods as Tabby:
Using item() method multiple times:
Using items() method with array:
Handling Payment Events
The package uses Laravel Events to handle payment events. This allows you to listen to payment events in your application without modifying the package code.
Available Events
The package dispatches the following events:
MLQuarizm\PaymentGateway\Events\PaymentSuccess- Dispatched when a payment is successfulMLQuarizm\PaymentGateway\Events\PaymentFailed- Dispatched when a payment failsMLQuarizm\PaymentGateway\Events\PaymentCancelled- Dispatched when a payment is cancelledMLQuarizm\PaymentGateway\Events\PaymentPending- Dispatched when a payment is pending
Listening to Events
Register event listeners in your app/Providers/EventServiceProvider.php:
Creating Event Listeners
Create listeners using Artisan:
Example listener:
Using Closures (Alternative)
You can also use closures in EventServiceProvider:
How to Use Callback and Webhook
The package handles payment results in two ways: callback (when the user is sent back to your site after paying) and webhook (when the gateway sends a server-to-server request). Both use the same logic to update the transaction and fire events; only the entry point and response differ.
Callback (user redirect)
What it is: After the user completes or cancels payment on Tabby/Tamara, the gateway redirects the user to a URL you provide. That URL must be your app so the package can process the result and then send the user to your success/error/cancel page.
How to use it:
-
Register the callback URL with the gateway
In Tabby/Tamara merchant settings (and in your.env), set:- Success URL:
https://yourdomain.com/payment/callback/tabby(or.../payment/callback/tamara) - Failure URL: same path
- Cancel URL: same path
The package uses one route and decides success/failure/cancel from the request data.
- Success URL:
-
Exclude the callback from CSRF
Inapp/Http/Middleware/VerifyCsrfToken.phpadd: -
Set redirect URLs in config
So the user is sent to your status page after processing, set in.env(or config):TABBY_REDIRECT_SUCCESS_URL,TABBY_REDIRECT_FAILURE_URL,TABBY_REDIRECT_CANCEL_URLTAMARA_REDIRECT_SUCCESS_URL, etc.
Example:https://yourdomain.com/payment-status/success/ar.
The callback always redirects (never returns JSON). If these are not set, it usesPAYMENT_REDIRECT_FALLBACK_URLor the app root with?status=...&gateway=....
- Flow
User finishes on gateway → gateway redirects toGET /payment/callback/{gateway}(with query params) → package runsHandlePaymentAction, updatesPaymentTransaction, fires events → package redirects to your redirect_success_url / redirect_error_url / redirect_cancel_url.
Route: GET|POST /payment/callback/{gateway} (e.g. payment/callback/tabby, payment/callback/tamara).
Webhook (server-to-server)
What it is: Tabby/Tamara send an HTTP POST to your server to notify payment status. No user is in the browser; the gateway calls your URL directly.
How to use it:
-
Register the webhook URL with the gateway
In Tabby/Tamara merchant/dashboard settings, set the webhook URL to:https://yourdomain.com/webhooks/payment/tabbyhttps://yourdomain.com/webhooks/payment/tamara
-
Exclude the webhook from CSRF
Same as above: addwebhooks/payment/*toVerifyCsrfToken::$except. -
Configure verification (recommended)
- Tamara: set
TAMARA_NOTIFICATION_TOKENin.env; the package verifies the JWT. - Tabby: set
TABBY_SECRET_KEYand optionallyTABBY_WEBHOOK_VERIFY_SIGNATURE=truefor HMAC verification.
- Tamara: set
- Flow
Gateway sendsPOST /webhooks/payment/{gateway}→ package verifies signature/token → runs sameHandlePaymentAction, updates transaction, fires same events → returns 200 so the gateway does not retry.
Route: POST /webhooks/payment/{gateway}.
Summary: callback vs webhook
| Callback | Webhook | |
|---|---|---|
| Who calls | User’s browser (redirect from gateway) | Gateway’s server |
| Method | GET (or POST) | POST |
| Route | /payment/callback/{gateway} |
/webhooks/payment/{gateway} |
| Response | Redirect to your redirect_*_url or JSON | Always 200 (body not used by gateway) |
| Logic | Same: find transaction, update status, fire events | Same |
Reacting to payment result (both callback and webhook)
Listen to package events; they are fired for both callback and webhook:
Routes
The package automatically registers:
GET|POST /payment/callback/{gateway}– Callback (public): redirects by default to package status Blade.GET /payment-gateway/status/{status}– Package status page (public Blade: success / error / cancel); redirect URL from env, with order id when set.POST /webhooks/payment/{gateway}– Webhook: gateway server-to-server notification.
Webhook Signature Verification
The package includes built-in webhook signature verification for security. All webhooks are automatically verified before processing.
Tamara Webhook Verification
Tamara uses JWT tokens for webhook verification. The token can be provided in:
- Query parameter:
?tamaraToken=... - Authorization header:
Bearer <token>
The package verifies:
- JWT token format (header.payload.signature)
- Signature using HMAC-SHA256 with
notification_token - Token expiration (
expclaim)
Configuration:
Tabby Webhook Verification
Tabby uses HMAC-SHA256 signature verification. The signature is expected in:
X-Tabby-Signatureheader (preferred)X-Signatureheader (fallback)Signatureheader (fallback)
Configuration:
Note: By default, Tabby webhook signature verification is disabled (TABBY_WEBHOOK_VERIFY_SIGNATURE=false) to maintain backward compatibility. Enable it when you're ready to enforce signature verification.
How It Works
- Webhook request arrives at
POST /webhooks/payment/{gateway} WebhookVerificationServiceverifies the signature/token- If verification fails, the request is rejected (but returns 200 to prevent gateway retries)
- If verification succeeds, the request is processed normally
Custom Verification
You can extend WebhookVerificationService to add custom verification logic for other gateways or modify existing verification methods.
Payment Transaction Model
The PaymentTransaction model uses polymorphic relationships, so it can be associated with any model:
License
MIT
All versions of payment-gateway with dependencies
laravel/framework Version ^10.0|^11.0
illuminate/support Version ^10.0|^11.0
illuminate/http Version ^10.0|^11.0
illuminate/database Version ^10.0|^11.0