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 Ogone Bundle Laravel Package

ets/payment-ogone-bundle

Ogone payment provider for JMSPaymentCoreBundle, letting Symfony apps process payments through the Ogone gateway via JMSPaymentCore. Install and usage docs included.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the reality check: this is a Symfony bundle, not a Laravel package. It extends JMSPaymentCoreBundle and wires itself through Symfony's DI container, PaymentInstruction/Plugin abstractions, and event dispatchers. You cannot composer require it into a Laravel app and expect it to boot. What you can do is use it as a reference implementation — or, in a hybrid shop, pull in jms/payment-core-bundle plus this provider and drive them from a thin Laravel bridge.

Minimal path for a Laravel dev:

  1. Read Resources/doc/install.rst and Resources/doc/usage.rst on GitHub — they're short and are the only real docs.
  2. Read the DI extension and DependencyInjection/Configuration.php to see the exact config keys (PSPID, API user/password, SHA passphrase, mode).
  3. Read the plugin classes (OgoneDirectLinkPlugin for server-to-server, the e-commerce/redirect plugin for hosted-page checkout) — this is where the signing logic lives.
  4. Decide: (a) port the signing + request-building code into your own Laravel service, or (b) keep a Symfony microservice for Ogone and call it from Laravel.

First real use case: a redirect checkout. Build an order/payment instruction, hand it to the provider plugin, get back the Ogone orderstandard.asp form/redirect URL with signed parameters, send the customer there, then handle Ogone's POST-back (feedback) on a webhook route.

Where to look first: Resources/doc/usage.rst → the plugin class → the signature helper. Everything else is Symfony plumbing you'll throw away.

Implementation Patterns

Porting the provider as a Laravel service

Wrap the bundle's request-building and signature logic in a single injectable service so controllers stay dumb:

final class OgoneGateway
{
    public function __construct(private array $config) {}

    public function redirectUrl(Order $order): string
    {
        $params = [
            'PSPID'       => $this->config['pspid'],
            'ORDERID'     => $order->reference,
            'AMOUNT'      => (int) round($order->total * 100), // minor units
            'CURRENCY'    => '978', // EUR, ISO 4217 numeric
            'LANGUAGE'    => 'en_US',
            'ACCEPTURL'   => route('ogone.accept'),
            'DECLINEURL'  => route('ogone.decline'),
            'EXCEPTIONURL'=> route('ogone.exception'),
            'CANCELURL'   => route('ogone.cancel'),
        ];

        $params['SHASIGN'] = $this->sign($params);

        return $this->config['endpoint'].'?'.http_build_query($params);
    }
}

Feedback webhook

Ogone POSTs back to your ACCEPTURL. Treat that POST as untrusted until SHASIGN verifies (with the feedback passphrase, which is often different from the SHA-IN passphrase — check your Ogone account).

Route::post('/ogone/feedback', function (Request $request, OgoneGateway $gw) {
    abort_unless($gw->verify($request->post()), 403);

    $order = Order::where('reference', $request->input('orderID'))->firstOrFail();

    if ($request->input('STATUS') === '5') {      // 5 = payment accepted
        $order->markPaid($request->input('PAYID'));
    }

    return response('OK');
})->withoutMiddleware(['csrf']); // Ogone won't send your token

Mapping JMSPaymentCore concepts

If you're keeping the Symfony stack around:

  • PaymentInstruction → your basket/order snapshot + amount/currency.
  • Plugin::approve($instruction) → performs the Ogone call (DirectLink) or produces the redirect.
  • Plugin::complete($instruction) on feedback → marks the instruction complete and raises the bundle's events.
  • Subscribe to those events and forward them into Laravel (queue job, HTTP call, or shared DB row) so your app reacts to payment.success without importing Symfony's dispatcher.

Day-to-day workflow tips

  • Keep signing in one class, unit-tested against Ogone's published test vectors, and reuse it for both request and feedback verification.
  • Store the raw request/response payload (JSON blob on the order) — it makes support tickets survivable.
  • Drive environment from config: OGONE_PSPID, OGONE_SHA_IN, OGONE_SHA_OUT, OGONE_MODE=test|prod. Test endpoints are secure.ogone.com/ncol/test/....
  • Use a Laravel job (queued) for post-payment side effects so the webhook returns fast and Ogone doesn't retry.
  • Idempotency: key your order-update logic on PAYID/ORDERID so repeated feedback POSTs don't double-fulfil.

Gotchas and Tips

The bundle will not install cleanly in Laravel. It requires Symfony's HTTP kernel, DI, and jms/payment-core-bundle. Attempting to load it via a Laravel service provider will fail on missing Symfony services. Extract, don't integrate.

Signature ordering rules are unforgiving. Ogone's SHASIGN is computed over parameters sorted alphabetically by key, case-insensitively, joined as KEY=VALUE pairs — excluding empty values and never including SHASIGN itself. The bundle's helper does this correctly; copy it rather than reinventing if you port. Watch the case: ACCEPTURL vs accepturl has bitten plenty of people.

SHA-1 vs SHA-256. Ogone accounts can be configured for either. The digest algorithm must match the account setting or every payment fails signature validation with no useful error message. This is the single most common "it works in test but not prod" cause.

Amounts are in minor units and currency is numeric. AMOUNT is cents (19.99 → 1999) and CURRENCY is ISO-4217 numeric (978 for EUR), not EUR. Passing the wrong one gives a generic error page at Ogone, not an API error.

Passphrases are per-account and per-configuration. SHA-IN (request signing) and SHA-OUT (response signing) are distinct, and the "feedback" passphrase may differ from the e-commerce one. If verification fails in staging, check which passphrase type the account uses.

Webhooks need CSRF exemption and a 200 response body. Ogone expects a plain OK/200; anything else triggers retries. Always verify the signature before touching the database, but persist the raw payload even for invalid ones so you can debug.

Old Symfony baggage. Last release is 2025, but the codebase carries legacy Symfony patterns (annotations, older component APIs). If you're reading it for reference, prefer the newer branches/tags and cross-check against the Symfony version constraints in composer.json rather than assuming modern style.

Status codes matter more than the redirect. Customers will hit ACCEPTURL even for declined payments in some configurations. Always branch on STATUS (5 = accepted, 9 = cancelled, 2 = declined-ish) rather than trusting which URL Ogone redirected to.

Only 12 stars and zero dependents means thin community support. There are no Stack Overflow answers waiting for you; expect to read the plugin source, and keep your own tests around the signature and feedback parsing — they're the parts that break silently.

Extension points you can still learn from: the bundle separates "plugin" (payment flow) from "signature/parameter" helpers and config. Mirror that split in your Laravel port — a OgoneSigner, an OgoneGateway, and a OgoneFeedbackHandler — and you'll be able to swap Ogone for Stripe/Adyen later without touching controllers.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource