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

Shaparak Laravel Package

php-monsters/shaparak

PHP package for integrating Iran's Shaparak payment gateway into Laravel or standalone PHP apps. It handles payment requests, gateway redirects, and transaction verification, making it simple to accept and confirm online payments with a clean, configurable setup.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a gateway handler for Iranian IPG (Internet Payment Gateway) providers — the local equivalent of Stripe/PayPal wrappers. Install via Composer:

composer install php-monsters/shaparak

Most packages of this shape ship a service provider with auto-discovery, so nothing is needed in config/app.php on Laravel 9+. Publish the config first — this is the file you will live in:

php artisan vendor:publish --provider="PhpMonsters\Shaparak\ShaparakServiceProvider"

That should drop a config/shaparak.php containing driver entries (one per gateway — Zarinpal, IDPay, Pay.ir, Zibal, etc.), each with API keys, terminal IDs, and a callback URL pointing at a route in your app.

Your first real use case is the standard two-leg payment flow:

  1. Request — build a payment from your order, redirect the user to the gateway:
    $payment = Shaparak::driver('zarinpal')
        ->amount(50000)          // verify units: rials vs. tomans!
        ->callback(route('payment.callback'))
        ->request();
    
    return redirect($payment->redirectUrl());
    
  2. Callback — receive the user back, verify the transaction, update your order, redirect the user onward.

Look first at the config file, then at whatever the Shaparak facade resolves to (usually a Manager extending Illuminate\Support\Manager). That manager tells you exactly which driver names are valid. The callbacks in the package's docblocks/README are usually self-sufficient minimal examples — copy them before wiring anything into your own domain model.

Implementation Patterns

Driver-per-gateway via Laravel's Manager. Expect Shaparak::driver('name') to behave like Cache::store(): shared driver config, per-call fluent options. Treat the fluent builder as immutable-ish per request — create a fresh payment per transaction rather than reusing a builder.

Separate "request" and "verify" into two methods on your app. The cleanest integration is a PaymentService in your domain that owns order state, and calls the package only for the wire protocol:

class PaymentService
{
    public function start(Order $order, string $gateway): RedirectResponse
    {
        $result = Shaparak::driver($gateway)
            ->amount($order->total_rial)
            ->orderId($order->id)
            ->callback(route('payment.callback', ['order' => $order->id]))
            ->request();

        $order->update(['authority' => $result->authority(), 'gateway' => $gateway]);

        return redirect($result->redirectUrl());
    }

    public function verify(Order $order, Request $request): bool
    {
        $result = Shaparak::driver($order->gateway)
            ->amount($order->total_rial)
            ->authority($request->input('Authority') ?? $order->authority)
            ->verify();

        return $result->isSuccessful();
    }
}

One callback route, dispatched by gateway. Gateways return different query param names (Authority, authority, trackId, token). Route through a controller that looks up the order, resolves the driver from the order record, and reads params defensively (the driver should normalize, but you will hit inconsistencies).

Multiple gateways as fallbacks. A common production pattern: try the user's chosen gateway; on a GatewayException before redirect, fail over to a second driver. Do this only on the request leg — never fail over on the verify leg or you double-charge.

Testing. Wrap the package behind your PaymentService interface and fake that — most Shaparak packages don't ship a built-in fake() like Cashier does. If they do expose an Http::fake seam internally, prefer faking at the HTTP layer; the drivers hit well-known endpoints.

Gotchas and Tips

  • Rial vs. Toman. Iranian gateways quote and charge in rials, but your DB/UI almost certainly uses tomans (1 toman = 10 rials). Every amount mismatch on the callback is a failed verify. Normalize amounts at the service boundary and never read $request->amount from the callback — use your stored order total.
  • Verify is not idempotent per gateway spec. If a user refreshes the callback, you can double-verify. Guard with a payments table row in a verifying state and short-circuit repeat calls; most gateways return "already verified" errors that you must treat as success if the amount/authority match.
  • Callback must not trust the query string. The whole point of verify() is that you send authority + amount to the gateway and get a signed confirmation back. If your code says if ($request->Status === 'OK') you have a vulnerability. Always call verify.
  • Config caching breaks runtime config. If you call config(['shaparak.drivers.x.merchant_id' => ...]) per-tenant, php artisan config:cache in production will silently ignore it. Pass credentials through the driver builder instead, or bind a per-tenant config.
  • Timeouts and network errors. Iranian gateways are flaky; wrap request() and verify() in try/catch for connection exceptions and surface a friendly "try another gateway" message. Default Guzzle timeout is often too aggressive at 5s — bump it in whatever HTTP client config the package exposes.
  • Sandbox modes vary per driver. Each Iranian gateway has its own staging/sandbox endpoint and often a magic sandbox merchant ID. Check the config for a sandbox boolean per driver; there's no unified switch.
  • SOAP vs. REST. Some Iranian gateways (Behpardakht/Mellat in particular) are SOAP. If you see SoapClient internals, remember Http::fake won't intercept them — mock at your service boundary instead.
  • Extension point is the driver. If you need a gateway the package doesn't ship, extend the base driver class (AbstractDriver or similar) and register it under shaparak.drivers in config. This is the intended extension seam — do not fork.
  • Log the raw authority + verification response (not card numbers / CVV2) — Iranian gateway support will demand the referenceId/rrn from a failed verification, and by then you'll have lost the callback request context.
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.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums