A simple and convenient way to connect your app to Iranian payment providers.
To view the Persian documentation, please refer to README_FA.md.
برای مشاهده راهنمای فارسی، لطفاً به فایل README_FA.md مراجعه کنید.
- PHP version
8.3or higher - Laravel
^11.44, or^12.23
| Gateway Name (EN) | Gateway Name (FA) | Gateway Website | Gateway Key | Version |
|---|---|---|---|---|
| Behpardakht | به پرداخت ملت | behpardakht.com | behpardakht |
1.0.0 |
| Sep | سامان کیش (سپ) | sep.ir | sep |
1.0.0 |
| Zarinpal | زرین پال | zarinpal.com | zarinpal |
1.0.0 |
| IDPay | آی دی پی | idpay.ir | id_pay |
1.0.0 |
| Pep | پرداخت الکترونیک پاسارگاد | [pep.co.ir] | pep |
Unreleased |
Caution
Gateways have different rules for pending verifications and reversals. Please check gateways_note_en.md.
To install the package via Composer, run:
composer require amyavari/iran-payment-laravelTo publish all vendor files (config and migrations):
php artisan iran-payment:installNote: To create tables from migrations:
php artisan migrateTo publish only the config file:
php artisan vendor:publish --tag=iran-payment-configTo publish only the migration file:
php artisan vendor:publish --tag=iran-payment-migrationsNote: To create tables from migrations:
php artisan migrateTo configure payment gateways, add the following to your .env file:
# Default gateway
PAYMENT_GATEWAY=<default_gateway>
# Default application currency
APP_CURRENCY=<Toman or Rial>
# Whether to use sandbox mode instead of the real gateway
PAYMENT_USE_SANDBOX=<true or false>
# Per-gateway configuration (callback URL and credentials)
# See the "gateways" section in config/iran-payment.phpNotes:
- For the
PAYMENT_GATEWAY, refer to thegateway Keycolumn in the List of Available Payment Gateways. - For each gateway’s callback URL and credentials, define the required keys under your desired gateway(s) in the
gatewayssection of config/iran-payment.php
You can create a new payment using the facade provided by the package:
use AliYavari\IranPayment\Facades\Payment;
// Using the default gateway (uses the callback URL from config)
$payment = Payment::create(int $amount, ?string $description = null, ?string|int $phone = null);
// Using the default gateway (define the callback URL at runtime)
$payment = Payment::callbackUrl(string $callbackUrl)->create(...);
// Using a specific gateway (uses the callback URL from config)
$payment = Payment::gateway(string $gateway)->create(...);
// Using a specific gateway (define the callback URL at runtime)
$payment = Payment::gateway(string $gateway)->callbackUrl(string $callbackUrl)->create(...);Note: For the $gateway, refer to the gateway Key column in the List of Available Payment Gateways.
In all calls to a gateway’s API (all methods in this package), you can check the latest status and response using the following methods:
$payment->successful(); // bool
$payment->failed(); // bool
// Get the error message (returns `null` if successful)
$payment->error(); // string|null
// Get the raw gateway response (useful for debugging)
$payment->getRawResponse(); // string|arrayThe package can automatically store payments and keep them in sync during later API calls such as verification, or reversal.
If you prefer full control, Manual Store approach.
Enable automatic storage by chaining store() before calling create():
use AliYavari\IranPayment\Facades\Payment;
// Store the payment and associate it with a payable Eloquent model
Payment::store(Model $payable)->create(...);
Payment::{other configurations}->store(Model $payable)->create(...);Notes:
- For automatic storage, you must publish and run the migration files. See Publish Vendor Files.
- If payment creation fails, no record will be stored.
- Once enabled, the package will automatically update the payment record in subsequent API calls.
After a payment is created, and during any subsequent API calls such as verify(), or reverse(), you can access the underlying payment model:
$payment->getModel(); // \AliYavari\IranPayment\Models\Payment
// Access the associated payable model
$payment->getModel()->payable;To see all available attributes, refer to src/Models/Payment.php
When using automatic storage, add the AliYavari\IranPayment\Concerns\HasPayment trait to your payable model to track its payments:
// Example payable model (Course)
namespace App\Models;
use AliYavari\IranPayment\Concerns\HasPayment;
use Illuminate\Database\Eloquent\Model;
final class Course extends Model
{
use HasPayment;
//
}
// Payments relationship (MorphMany)
$course->payments(); // AliYavari\IranPayment\Models\PaymentNote: For more information about this relationship, see Eloquent relationships: one-to-many polymorphic.
The Payment model provides query scopes for common payment states:
use AliYavari\IranPayment\Models\Payment as PaymentModel;
// Verified and successful payments
PaymentModel::query()->successful()->...
// Verified and failed payments
PaymentModel::query()->failed()->...
// Pending (unverified) payments
PaymentModel::query()->pending()->...
// Via a payable model using HasPayment
$course->payments()->successful()->...
$course->payments()->failed()->...
$course->payments()->pending()->...If you want full control over storing and tracking payments, you can use these methods:
// Data required by the gateway for verification (`null` if payment creation failed)
$payment->getGatewayPayload(); // array|null
// Gateway key
$payment->getGateway(); // string
// Unique transaction ID used for tracking in your database (`null` if payment creation failed)
$payment->getTransactionId(); // string|nullTo redirect user to the gateway’s payment page, use the data provided by the following method:
$redirectData = $payment->getRedirectData(); // `null` if payment creation failed
// Redirect URL
$redirectData->url; // string
// Redirect method (POST, GET)
$redirectData->method; // string
// Redirect payload (POST body or GET query params)
$redirectData->payload; // array
// Required HTTP headers
$redirectData->headers; // array
// Get all redirect information as an array
$redirectData->toArray(); // arrayAfter the user is redirected back to your application from the gateway, you can verify the payment using these methods:
Notes:
- After calling
verify(), orreverse(), you can use the methods in Checking API Call Status to check the result of the API call. - If the payment was stored in the database using this package, these methods will automatically update the payment record. To access the underlying payment model, see Automatic Store
use AliYavari\IranPayment\Facades\Payment;
// Create a gateway instance from callback data
$payment = Payment::gateway(string $gateway)->fromCallback(array $callbackPayload);If you used the internal automatic storage
// Call verify without any arguments
$payment->verify();If you stored the payment manually,
// To find the payment in your database
$payment->getTransactionId();
// Call verify with the stored gateway payload
$payment->verify(array $gatewayPayload);To reverse the payment:
// Reverse or refund the payment (call if verification fails)
$payment->reverse();
// Let the package handle reverse automatically when needed
$payment
->autoReverse(bool $autoReverse = true)
->verify(...); // Manual or automatic storageNotes:
- To get
$callbackPayload, this package provides basicFormRequestclasses to validate callback data. These classes are located inAliYavari\IranPayment\Requests\<Gateway>Request. See Form Request classes - If auto-reverse is enabled, the Checking API Call Status applies to verification.
If the payment is successful, the following methods are available to retrieve additional payment details:
// Get the reference number assigned to the transaction by the bank. (`null` if payment verification failed)
$payment->getRefNumber(); // string|null
// Get user's card number used to pay. (`null` if payment verification failed)
$payment->getCardNumber(); // string|nullTo sanitize and validate callback data from each gateway, this package provides simple FormRequest classes.
You can use them like this (using the sep gateway as an example):
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use AliYavari\IranPayment\Http\Requests\SepRequest;
use App\Http\Controllers\Controller;
use Illuminate\Http\RedirectResponse;
final class SepVerificationController extends Controller
{
public function update(SepRequest $request): RedirectResponse
{
$callbackData = $request->validated();
// Verification logic, product delivery, etc.
}
}Available Form Request classes:
// Behpardakht
use AliYavari\IranPayment\Http\Requests\BehpardakhtRequest;
// Sep
use AliYavari\IranPayment\Http\Requests\SepRequest;
// Zarinpal
use AliYavari\IranPayment\Http\Requests\ZarinpalRequest;
// IDPay
use AliYavari\IranPayment\Http\Requests\IdPayRequest;Sometimes the user does not return to your website after completing the payment. In this case, you should use the noCallback() method instead of fromCallback(). All other steps remain the same.
use AliYavari\IranPayment\Facades\Payment;
$payment = Payment::gateway(string $gateway)->noCallback(string $transactionId);If you are using Automatic Store, you can directly rebuild the gateway payment instance from the stored model:
$payment = $paymentModel->toGatewayPayment();Note: Some gateways (mainly Shaparak-based gateways) automatically reverse the transaction if the callback is not received, while others allow verification without a callback. This package applies each gateway’s rules internally.
For local development or automated tests, you can fake payment responses so no real transactions are made. This allows you to test success, failure, and connection errors safely.
Note: All methods are chainable. Examples below show single calls for clarity.
use AliYavari\IranPayment\Facades\Payment;
use AliYavari\IranPayment\Dtos\PaymentRedirectDto;
// Default gateway
$fake = Payment::fake();
// Specific gateway
$fake = Payment::fake($gateway);Note: For the $gateway, refer to the gateway Key column in the List of Available Payment Gateways.
$fake->successfulCreate($rawResponse = 'Creation raw response', $gatewayPayload = ['payload' => 'test value'], ?PaymentRedirectDto $redirectData = null);
$fake->failedCreate($rawResponse = 'Creation raw response', $errorCode = 0, $errorMessage = 'Creation failed');
$fake->failedConnectionCreate($message = 'Creation connection failed');Notes:
- If
$gatewayPayloadis null, a gateway‑specific default payload (correct keys, dummy values) is used. - If
$redirectDatais null, this default is returned:
'url' => 'https://gateway.test',
'method' => 'POST',
'payload' => ['status' => 'successful'],
'headers' => ['X-IranPayment-Fake' => 'true'],$fake->successfulVerify($rawResponse = 'Verification raw response', $refNumber = '123456789', $cardNumber = '1234-****-****-1234');
$fake->failedVerify($rawResponse = 'Verification raw response', $errorCode = 0, $errorMessage = 'Verification failed');
$fake->failedConnectionVerify($message = 'Verification connection failed');Note: The fake gateway does not validate gateway payloads or callback data. You can only simulate an invalid callback exception by explicitly forcing it:
$fake->invalidCallback($message = 'Invalid callback data');$fake->successfulReverse($rawResponse = 'Reversal raw response');
$fake->failedReverse($rawResponse = 'Reversal raw response', $errorCode = 0, $errorMessage = 'Reversal failed');
$fake->failedConnectionReverse($message = 'Reverse connection failed');Note: If you set behavior for the same gateway and method multiple times, only the last definition will take effect.
Thank you for considering contributing to the Iran Payment Laravel! The contribution guide can be found in the CONTRIBUTING.md.
Iran Payment Laravel was created by Ali Mohammad Yavari under the MIT license.
