kiakaha/chargily-v2
Laravel package for integrating Chargily Pay v2, Algeria's online payment gateway. Provides a simple API for creating checkout sessions, handling payments and verifying webhooks, so you can accept CIB and Edahabia card payments in your PHP application with minimal setup.
composer require chargily/epay-symfony (confirm the exact package name from Packagist — the release note only states "Chargily V2 Epay for symfony").*Client or *Api service registered via a bundle extension, not a Laravel facade.AppServiceProvider's register() so you can inject it.DependencyInjection/ folder to see which constructor arguments the client expects — that tells you exactly what to bind in Laravel.Bind the client in a service provider
// AppServiceProvider::register()
$this->app->singleton(ChargilyClient::class, fn () => new ChargilyClient(
config('services.chargily.secret'),
config('services.chargily.mode'), // 'test' | 'live'
));
Keep credentials in config/services.php and .env, never in the package config file.
Wrap it in your own gateway class
Don't call the package client from controllers. Create App\Services\ChargilyGateway with methods like createCheckout(Order $order): CheckoutResult and verifyWebhook(Request $request): bool. This isolates the Symfony-ism and gives you one place to swap implementations or add retries/logging.
Checkout flow
pending state with a generated idempotency key.redirect()->away($checkoutUrl) — do not use a relative redirect, the URL is external.Webhook handling
Route::post('/webhooks/chargily', ChargilyWebhookController::class)
->withoutMiddleware([VerifyCsrfToken::class]);
Then, in the controller:
$request->getContent()), not the parsed array.403 and log it.if ($payment->status === 'paid') return response()->noContent();).200 quickly; dispatch a queued job for anything slow (emails, provisioning, invoice generation).Status reconciliation
Never trust the redirect/success URL alone — the customer can hit it without paying. Treat the webhook as the source of truth, and optionally add a chargily:reconcile artisan command that polls pending payments older than N minutes.
Testing
Since there's no Laravel fake provided, wrap the client behind your ChargilyGateway interface and bind a fake in tests. For webhook tests, build a payload, compute the signature with your test secret, and $this->call('POST', ..., [], [], [], ['HTTP_Signature' => $sig], $json).
Http client integration. Don't run php artisan vendor:publish expecting anything. Manual wiring is required, and bundle auto-discovery won't help you.HttpClient, you won't get Laravel's Http fake, retry macros, or event hooks. Wrap calls and add your own timeout/retry (->retry(3, 200) on a Laravel-side wrapper, or configure the Symfony client's max_duration).5000 means 50.00 DZD or 5000 DZD. Getting this wrong by 100x is the single most common integration bug.$request->all(), which re-encodes differently and breaks HMACs. Always hash $request->getContent(). Also confirm the exact header name and hash algorithm from the docs — do not guess.withoutMiddleware; you'll see 419 errors in logs and assume the gateway is broken.PaymentSucceeded, PaymentFailed) from the webhook handler rather than relying on package callbacks.config() calls happen in a closure or a booted callback — reading env vars directly in a package constructor breaks under php artisan config:cache.401s that look like auth bugs.APP_URL misconfiguration (e.g. http://localhost) will pass in sandbox testing but break webhooks in production — use route() with a properly configured APP_URL or ngrok/expose locally.^1.0 and read the diff between tags before upgrading — there's no evidence yet of a stable BC policy.ChargilyGateway adapter is cheaper than fighting a bundle's DI container inside Laravel.Http::withToken(...) implementation is a reasonable escape hatch and removes the Symfony dependency entirely.How can I help you explore Laravel packages today?