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

Payment Sips Bundle Laravel Package

kptive/payment-sips-bundle

A Symfony bundle for integrating the SIPS (Atos Worldline) payment gateway, providing configuration and services to process payments. Check maintenance status and Symfony/PHP compatibility before adopting.

View on GitHub
Deep Wiki
Context7

Getting Started

Look at the source before you look at the install docs. This is a Symfony 2 bundle built on JMSPaymentCoreBundle, not a Laravel package. There is no composer require path into a Laravel app that ends with working code — the bundle relies on Symfony bundle registration, the DI container, YAML/XML service definitions, and JMS's PaymentPluginInterface. Read it as a reference implementation of the SIPS wire protocol, then port the ~200 lines that matter into a first-party class.

Files worth reading first, in order:

  • The SipsPlugin class (extends JMS AbstractPlugin) — see exactly what approve() / approveAndDeposit() send to the gateway.
  • The service/config definitions — reveals the required merchant parameters (merchant id, pathfile path, currency, language, normal/error return URLs).
  • The response-handling code — how the DATA= payload returned by SIPS is decoded and mapped to a status.

The key architectural fact: this bundle shells out to Atos' SIPS CGI binaries (request and response executables) rather than speaking HTTP. Your port should do the same or replace it with the bank's HTTP connector — confirm which generation your contract provisions before writing anything.

First use case — a Laravel spike:

// config/sips.php
return [
    'merchant_id' => env('SIPS_MERCHANT_ID'),
    'pathfile'    => env('SIPS_PATHFILE'),
    'currency'    => 'EUR',
    'mode'        => env('SIPS_MODE', 'TEST'),
];

// app/Payments/SipsGateway.php
class SipsGateway
{
    public function authorize(Order $order): string
    {
        // build parm string from merchant_id, amount (minor units),
        // currency, order ref; invoke the SIPS `request` binary;
        // return the redirect URL / auto-submitting form HTML
    }

    public function handleReturn(Request $request): PaymentResult
    public function handleCallback(Request $request): PaymentResult
}

Persist the gateway reference (order_id / transaction id) before redirecting the customer.

Implementation Patterns

Wrap it behind your own interface, always. The day-to-day value is the protocol detail, not the class hierarchy. Define PaymentGateway in your app with authorize(), handleReturn(), handleCallback(), so the SIPS implementation is swappable the day Worldline migrates you.

Two distinct flows — handle them separately:

Flow Trigger Trust level What to do
Return Customer's browser lands back on your normal_return_url Untrusted Display result UI; do not mark the order paid from here alone
Callback SIPS server posts to your callback URL Verify signature, then trust Update order state, queue downstream work, ACK fast

The bundle supports both; a common port mistake is only wiring up the return URL and letting the callback rot.

Recommended Laravel package shape:

// Service provider binds config + gateway
$this->app->singleton(PaymentGateway::class, SipsGateway::class);
$this->mergeConfigFrom(__DIR__.'/../config/sips.php', 'sips');

// Domain events, fired from the callback handler only
PaymentSucceeded::class;  // includes gateway reference + amount
PaymentFailed::class;

Callback handler — the pattern that works:

public function handleCallback(Request $request): Response
{
    $data = $this->sips->decode($request->input('DATA'));

    if (! $this->sips->verifySignature($data, $request->input('seal'))) {
        Log::warning('sips.signature_mismatch', ['ref' => $data['order_id'] ?? null]);
        return response('bad signature', 400);
    }

    // Idempotent on gateway reference
    $txn = Transaction::firstOrCreate(
        ['gateway_ref' => $data['transaction_id']],
        ['order_id' => $data['order_id'], 'amount' => $data['amount']]
    );

    if ($txn->wasRecentlyCreated) {
        $txn->order->markPaid();
        event(new PaymentSucceeded($txn));
    }

    return response('OK', 200); // SIPS expects a fast 200
}

Request building — the fields that matter: merchant id, amount in the gateway's minor-unit convention, currency (ISO 4217 numeric), customer language, order reference, and the normal/error return URLs. Get these wrong and the callback will never arrive — the failure surfaces at the customer, not at request-build time.

Reconciliation cron, not optional. A scheduled job that polls unsettled transactions older than N minutes against the bank's reporting catches the "customer paid, callback lost" case. Write it before launch, not after the first incident.

Gotchas and Tips

The Laravel incompatibility is structural, not cosmetic. No bundle registration, no tag-based plugin discovery, no Symfony YAML service graph. If you try to composer require this into Laravel you will end up patching the bundle itself — a fork you now own with a second dead dependency (JMSPaymentCoreBundle) underneath.

Amount formatting is the #1 bug. SIPS uses minor units and decimal-comma conventions depending on locale. A €12.50 order can easily become 1250 or 12,50 or 0.125. Write a per-currency unit test asserting the exact byte string sent to the gateway.

Signature verification needs hash_equals, not ==. The bundle predates wide adoption of constant-time comparison; do not copy an == from it. Also decode the DATA= payload before comparing — a mismatch between raw vs. decoded is a classic false-failure.

Do not trust the return URL for payment confirmation. Browser refresh re-hits the return endpoint and will double-apply state if you let it. Make the return handler read-only; only the callback (or reconciliation) mutates order status.

The bank rotates pathfiles and endpoints unannounced. Your pathfile config must be reloadable without a deploy, and connection errors to the SIPS endpoint should be a distinct alert class from payment failures — otherwise an endpoint change looks like a payments outage.

Sandbox credentials are the critical path. Worldline/Atos sandbox provisioning often takes weeks and runs through the acquirer's onboarding desk, not GitHub. Start the credential request the same day you start the code spike; if the test creds don't arrive, the whole thing is blocked.

Shelling out to request/response binaries (as this bundle does) is fragile: binary path config, permission, cwd for the pathfile, and stderr swallowing all bite. Capture exit codes and stderr explicitly, and prefer the bank's HTTP connector if your contract offers one.

Log every gateway call with the reference and the raw response. When reconciliation and the bank disagree, the raw DATA blob and your outbound parm string are the only things that will resolve it.

Extend nothing in the bundle. Every feature request against this code (refunds, 3DS2, multi-currency, tokenisation) is a migration signal, not an enhancement ticket. Track it behind your PaymentGateway interface and swap providers at the boundary.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo