valiton/saferpay-bundle
Symfony bundle that integrates the Saferpay payment gateway into your application, offering configuration and services for handling Saferpay transactions, payment pages, and callbacks so you can accept online card payments without writing the integration glue yourself.
This is a Symfony bundle, not a Laravel package — if you're coming from Laravel, expect to translate the mental model (service container, config/packages/*.yaml, event subscribers) rather than config/*.php and package discovery.
Minimal path in:
composer require valiton/saferpay-bundle — then check composer.lock and the bundle's composer.json because the package is effectively abandoned (1 star, 0 dependents, last activity is old). Pin to an exact version and expect to fork it.config/bundles.php) add Valiton\SaferpayBundle\ValitonSaferpayBundle::class => ['all' => true]. On older projects this goes in AppKernel::registerBundles().valiton_saferpay:) — customer ID, terminal ID, API username/password, test/live flag. Look first at DependencyInjection/Configuration.php in the repo for the exact keys; the docs are thin.RedirectUrl, then Assert on the return URL to confirm the outcome before fulfilling the order. That's the canonical flow and everything else (capture, refund, cancel) hangs off it.Start reading at Resources/config/services.yml to see which concrete classes implement the CorePaymentBundle provider interface — that tells you the actual entry point your controllers should call.
Provider abstraction. Because this bundle is an extension to CorePaymentBundle, the idiomatic usage is not to call Saferpay's HTTP endpoints directly. Resolve the provider service from the container and let CorePaymentBundle's transaction/state model drive the flow. Check Resources/config/services.yml for service IDs and aliases — usually a single provider service is what you inject into a PaymentController.
Two-phase hosted checkout. Split the flow:
token, redirect to RedirectUrl.Status (AUTHORIZED, CAPTURED, PENDING, FAILED) before trusting the redirect parameters. Never fulfill on the redirect query string alone.Capture / refund as separate actions. For most card flows you'll authorize first and capture later (delayed capture). Wire capture into your fulfilment job, not the user request, so a Saferpay timeout doesn't roll back an order. Refunds are keyed off the original TransactionId.
Callback routes should be thin: validate the return parameters, call the bundle's Assert, then dispatch a domain event (OrderPaid, PaymentFailed). Keep Saferpay-specific DTOs out of your domain layer — map to your own enums.
Test mode as a config switch, not an if (app()->environment()). The bundle's terminal ID changes between test and live; treat terminal_id, customer_id, and username/password as environment-scoped secrets.
Idempotency. Saferpay's API accepts a RequestId header — feed it from your local payment UUID so retries don't double-charge. If the bundle doesn't expose this, that's a candidate for your fork.
composer.json require block against your Symfony version before investing. You may need symfony/http-foundation polyfills or a fork. Budget for reading the source, not the docs.1050). Currency and amount must match the value you assert later; mismatches fail the Assert silently in test mode.?status=success) are advisory and user-controllable. Only the Assert response is authoritative — check both Status and Type.trusted_proxies configured or the generated URL will be http://localhost.AUTHENTICATION_FAILED 401s — log the raw Saferpay response body before the bundle swallows it.GuzzleHttp\ClientInterface and configuring it via the framework.http_client if it supports it, otherwise bind a custom service.symfony/http-client middleware or a Guzzle log subscriber) around the bundle's service. Don't enable it in production — Saferpay request bodies can contain cardholder-adjacent data.decorates: in services.yaml) or fork the repository — the latter is more honest for anything beyond minor tweaks.six-group/saferpay-json-api (or the official Saferpay JSON API client) directly instead of trying to port this bundle.How can I help you explore Laravel packages today?