Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Zibal Laravel Package

jey/zibal

Laravel gateway integration for Zibal payments. Provides simple API to create payment requests, redirect users to Zibal, and verify transactions after callback. Includes configuration, service classes, and helpers to streamline checkout and order payment flows.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require jey/zibal
    

    Publish the config file (if needed):

    php artisan vendor:publish --provider="Jey\Zibal\ZibalServiceProvider"
    
  2. Configuration Edit .env with your Zibal API credentials:

    ZIBAL_API_KEY=your_api_key_here
    ZIBAL_API_URL=https://api.zibal.ir/v1
    
  3. First Use Case Generate a payment request in a controller:

    use Jey\Zibal\Facades\Zibal;
    
    public function createPayment()
    {
        $payment = Zibal::createPayment([
            'amount' => 10000, // 10,000 Rials
            'callback_url' => route('zibal.callback'),
            'description' => 'Order #12345',
            'metadata' => ['order_id' => 12345],
        ]);
    
        return redirect()->away($payment->getPaymentUrl());
    }
    
  4. Callback Handling Define a route for Zibal’s callback:

    Route::post('/zibal/callback', [PaymentController::class, 'handleCallback']);
    

    Verify the callback in your controller:

    public function handleCallback(Request $request)
    {
        $payment = Zibal::verifyCallback($request->all());
        if ($payment->isSuccessful()) {
            // Process successful payment
        }
    }
    

Implementation Patterns

Common Workflows

1. Payment Creation & Redirection

  • Use Zibal::createPayment() to generate a payment request.
  • Redirect users to the generated URL ($payment->getPaymentUrl()).
  • Store the tracking_code in your database for later verification.
$payment = Zibal::createPayment([
    'amount' => 50000,
    'callback_url' => route('zibal.callback'),
    'metadata' => ['user_id' => auth()->id(), 'product_id' => 42],
]);

session()->put('zibal_tracking_code', $payment->tracking_code);
return redirect()->away($payment->getPaymentUrl());

2. Verifying Payments

  • Use Zibal::verifyCallback() in your callback route to validate the payment.
  • Check $payment->isSuccessful() to confirm success.
public function handleCallback(Request $request)
{
    $payment = Zibal::verifyCallback($request->all());

    if ($payment->isSuccessful()) {
        // Update order status, send confirmation, etc.
        Order::find($payment->metadata->order_id)
            ->update(['status' => 'paid']);
    }

    return response()->json(['status' => 'success']);
}

3. Manual Verification (Polling)

  • If callback URLs are unreliable, manually verify payments using tracking_code:
$payment = Zibal::verifyPayment($tracking_code);
if ($payment->isSuccessful()) {
    // Process payment
}

4. Refunds

  • Initiate a refund using Zibal::refundPayment():
$refund = Zibal::refundPayment($tracking_code, [
    'amount' => 50000, // Full or partial refund
    'description' => 'Customer refund request',
]);

Integration Tips

Database Storage

  • Store tracking_code, amount, metadata, and status in your orders or payments table.
  • Example schema:
    Schema::create('payments', function (Blueprint $table) {
        $table->id();
        $table->string('tracking_code')->unique();
        $table->integer('amount');
        $table->json('metadata');
        $table->string('status')->default('pending');
        $table->timestamps();
    });
    

Webhook Retries

  • Implement a retry mechanism for failed callbacks (e.g., using Laravel Queues):
public function handleCallback(Request $request)
{
    try {
        $payment = Zibal::verifyCallback($request->all());
        // Process payment
    } catch (\Exception $e) {
        // Log and retry later
        ProcessFailedCallback::dispatch($request->all());
    }
}

Testing

  • Use Zibal’s sandbox environment (if available) or mock the facade for unit tests:
$this->mock(Zibal::class)->shouldReceive('createPayment')
    ->once()
    ->andReturn(new Payment(['tracking_code' => '12345', 'payment_url' => 'https://sandbox.zibal.ir/12345']));

Gotchas and Tips

Pitfalls

1. Callback Validation

  • Issue: Zibal’s callback may be retried multiple times. Always idempotently process payments (e.g., check status before updating).
  • Fix: Store the tracking_code and status in your database to avoid duplicate processing.
if (!$payment->isSuccessful() && $this->paymentExists($payment->tracking_code)) {
    return response()->json(['status' => 'already_processed']);
}

2. Amount Mismatches

  • Issue: The amount in the callback may differ from the original request due to fees or rounding.
  • Fix: Compare the amount in the callback with your stored value (allowing for minor differences).
$storedAmount = $this->getStoredAmount($payment->tracking_code);
if (abs($payment->amount - $storedAmount) > 100) { // Allow 100 Rial tolerance
    throw new \Exception('Amount mismatch detected');
}

3. Metadata Handling

  • Issue: metadata is passed as a string in callbacks. Use json_decode() to access it.
  • Fix: Decode the metadata before use:
$metadata = json_decode($payment->metadata);
$orderId = $metadata->order_id;

4. Timeouts

  • Issue: Zibal’s API may time out if the callback takes too long.
  • Fix: Keep your callback handler lightweight. Offload heavy processing to a queue.

Debugging Tips

1. Enable Logging

  • Add logging to track payment flows:
\Log::info('Zibal payment created', [
    'tracking_code' => $payment->tracking_code,
    'amount' => $payment->amount,
]);

2. Test with Sandbox

  • If Zibal offers a sandbox, test thoroughly before going live. Example sandbox URL:
config(['zibal.api_url' => 'https://sandbox.zibal.ir/v1']);

3. Check HTTP Status Codes

  • Inspect the HTTP response from Zibal’s API for errors:
try {
    $payment = Zibal::verifyPayment($tracking_code);
} catch (\GuzzleHttp\Exception\RequestException $e) {
    \Log::error('Zibal API error', [
        'response' => $e->getResponse()->getBody(),
        'tracking_code' => $tracking_code,
    ]);
}

Extension Points

1. Custom Payment Models

  • Extend the package’s Payment model to add custom logic:
namespace App\Models;

use Jey\Zibal\Models\Payment as BasePayment;

class Payment extends BasePayment
{
    public function order()
    {
        return $this->belongsTo(Order::class);
    }
}

2. Custom Callback Handler

  • Override the default callback behavior by binding your own handler:
Zibal::extend(function ($app) {
    $app->bind(\Jey\Zibal\Contracts\CallbackHandler::class, function () {
        return new CustomCallbackHandler();
    });
});

3. Add Webhook Events

  • Dispatch Laravel events for payment status changes:
// In your callback handler
event(new PaymentProcessed($payment));

4. Localization

  • Extend the package’s language lines for Persian or other locales:
// config/zibal.php
'locale' => 'fa', // Force Persian responses

5. Retry Logic for Failed Payments

  • Implement a job to retry failed payments after a delay:
class RetryFailedPayment implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue;

    public function handle()
    {
        $payment = Zibal::verifyPayment($this->trackingCode);
        if (!$payment->isSuccessful()) {
            $this->release(60); // Retry in 60 minutes
        }
    }
}
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo