lelivrescolaire/kptive-payment-sips-bundle
Symfony bundle integrating the Kptive SIPS payment library, adding Atos Worldline SIPS support to Symfony applications. It wires the payment services into the framework so you can handle SIPS payment requests and responses within your project.
Read this first: this is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no facade, no config/kptive_payment_sips.php. composer require will pull symfony/http-kernel + symfony/dependency-injection, the bundle will not be auto-discovered, and the Bundle::getContainerExtension() machinery has no counterpart in Laravel. Combined with the fact that the repo is archived, 0 stars, 0 dependents, the correct mental model is:
Treat
kptive-payment-sips-bundleas a reference implementation of the ATOS SIPS PayPage signing protocol, not as a dependency to install.
Minimal steps
composer.json.DependencyInjection/Configuration.php — this is the canonical list of everything SIPS needs: merchant ID, country code, currency, pathfile path, certificate path + passphrase, normal/abnormal return URLs, and the target SIPS endpoint (test vs. production).Data / Encode / Seal (or DATA / SIGNATURE on newer SIPS) fields.app/Services/Sips/ and delete the rest.First use case — PayPage redirect:
POST /checkout -> create Order, build signed payload, render auto-submit form (Blade)
POST /payment/sips/return -> verify seal, mark Order paid, redirect to thank-you
Map the bundle's config to your own config/sips.php:
return [
'endpoint' => env('SIPS_ENDPOINT', 'https://payment-webinit.simu.sips-atos.com/paymentInit'),
'merchant_id' => env('SIPS_MERCHANT_ID'),
'country' => env('SIPS_COUNTRY', 'FR'),
'currency' => env('SIPS_CURRENCY', '978'), // EUR, ISO 4217 numeric
'pathfile' => storage_path('app/private/sips/pathfile'),
'cert' => storage_path('app/private/sips/certificate.p12'),
'cert_pass' => env('SIPS_CERT_PASS'),
'return_url' => url('/payment/sips/return'),
];
Credentials come from the acquiring bank (Société Générale / ATOS), never from the repo.
Pattern A — Port, don't install (do this).
Copy RequestBuilder and ResponseParser into Laravel classes, inject config via constructor, and bind them in app/Providers/SipsServiceProvider.php. You keep the protocol knowledge (which is genuinely fiddly) and lose the container/config-loader baggage.
Pattern B — Sidecar microservice.
If you must use the bundle verbatim, stand up a throwaway Symfony app with the bundle installed behind two routes (/build, /callback) and call it from Laravel over HTTP. Cheaper than trying to boot a Symfony DI container inside Laravel. Only worth it for a one-off migration.
Checkout controller shape
public function pay(Order $order, SipsRequestBuilder $builder)
{
$payload = $builder->build([
'amount' => $order->total_cents, // integer minor units
'orderId' => $order->reference,
'customerEmail' => $order->email,
]);
return view('sips.redirect', compact('payload'));
}
The Blade view is a <form method="POST" action="{{ config('sips.endpoint') }}"> with hidden Data/Encode/Seal inputs and a window.onload = () => document.forms[0].submit().
Callback controller shape
public function callback(Request $request, SipsResponseParser $parser)
{
$result = $parser->parse($request->all()); // throws on bad seal
DB::transaction(function () use ($result) {
$order = Order::where('reference', $result->orderId)->lockForUpdate()->firstOrFail();
$order->update(['state' => $result->isSuccess() ? 'paid' : 'failed', 'sips_raw' => $result->raw]);
});
event(new PaymentReceived($order));
return redirect()->route('checkout.done', $order);
}
Integration tips:
transaction_id or a processed_at timestamp checked inside the transaction.app/Http/Middleware/VerifyCsrfToken.php ($except = ['payment/sips/return']) and never put auth middleware on it.sips:reconcile command that pulls the daily file and compares. This is usually more valuable than the redirect flow itself.tests/Fixtures/sips/ certificate pair.PaymentReceived / PaymentFailed so order, mail, and fulfilment logic stay decoupled from the controller.symfony/* constraints from the 2.x/3.x era will fight Laravel 10/11's transitive deps. This is the main reason to port instead of require.Resources/ directory. Always pass absolute paths from storage_path() / base_path() and check is_readable() at boot.Data string. Keys sorted, URL-encoded once. Any normalization, reordering, or double http_build_query() breaks it silently — SIPS will just reject the request with a generic code. Unit-test the builder against a known-good vector from the bank's tool.$request->all(); don't reach for $request->json().978, not EUR). Off-by-100 bugs are the classic first-day incident.APP_URL/TrustProxies is misconfigured you'll get http:// or an internal host and a silent 404 on the way back.Data, Encode, Seal) in a text column. Bank support will only investigate if you can quote the exact payload, and it's your only debugging surface.storage/logs/sips.log) from day one, not after the first production failure.enum/map from SIPS codes to your states. Don't str_contains the response. Log unknown codes rather than defaulting to "failed".Event::dispatch.How can I help you explore Laravel packages today?