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

Payum Ems Bundle Laravel Package

justlease/payum-ems-bundle

A Symfony bundle that integrates the EMS payment gateway with Payum, offering gateway configuration, payment creation, callback handling, and transaction status workflows for JustLease applications.

View on GitHub
Deep Wiki
Context7

Getting Started

First, know what you're actually installing. This is a Symfony bundle, not a Laravel package. There is no service provider, no config/payment.php to publish, no facade. If you composer require it into a Laravel app expecting it to boot, nothing will happen — the bundle's only job is DI wiring expressed through Symfony's Extension, Configuration, and services.yaml. Plan from the start to either run it inside a Symfony service (and call that from Laravel over HTTP, if needed) or drop the bundle and use the underlying justlease/payum-ems directly.

Look here first, in this order:

  1. justlease/payum-ems — GatewayFactory, Action/* (capture, status, notify), and the API client. This is the real logic. Count the actions; that tells you the supported surface in five minutes.
  2. The bundle's DependencyInjection/EmsExtension.php and Configuration.php — these declare the actual config keys. Since there's no documentation, this is your config reference. Don't guess option names.
  3. composer.json of both packages — for the Payum major (1.x vs 2.x behave very differently) and Symfony version constraints.

Install (Laravel, bypassing the bundle):

"repositories": [
  { "type": "vcs", "url": "[email protected]:justlease_nl/payumemsbundle.git" },
  { "type": "vcs", "url": "[email protected]:justlease_nl/payumems.git" }
],
"require": {
  "justlease/payum-ems": "dev-master#<commit-sha>"
}

You'll need Bitbucket auth (SSH deploy key or app password) in CI, and you should pin to a commit SHA — tags are unlikely. Skip the -bundle package entirely in Laravel; it buys you nothing without the Symfony kernel.

First use case — sandbox, end to end: wire the gateway by hand, run authorize → capture → refund against EMS's test environment, and save the raw request/response payloads as fixtures. Do this before writing any application code. It is the single highest-value hour you'll spend.

If you happen to be inside Symfony, the setup is conventional:

# config/packages/payum.yaml — keys must match Configuration.php, not the README
payum:
  gateways:
    ems:
      factory: ems
      merchant_id: '%env(EMS_MERCHANT_ID)%'
      merchant_key: '%env(EMS_MERCHANT_KEY)%'

Implementation Patterns

Pattern A — Symfony-native (the intended path). Register the bundle in bundles.php, configure the gateway, and drive everything through Payum's unified API ($gateway->execute(new Capture($token)), new Status(...), new Notify(...)). You get the factory, actions, and callback handling for free.

Pattern B — Laravel with Payum core (recommended if you already run Payum). Drop the bundle, keep payum/core + justlease/payum-ems, and express the bundle's registration as a service provider:

// app/Providers/PaymentServiceProvider.php
$this->app->singleton(GatewayRegistry::class, function () {
    $registry = new GatewayRegistry();
    $registry->register('ems', (new EmsGatewayFactory())->create([
        'merchant_id'  => config('services.ems.merchant_id'),
        'merchant_key' => config('services.ems.merchant_key'),
    ]));
    return $registry;
});

You also need a storage implementation. Payum ships a filesystem and Doctrine ORM adapter; in Laravel, write an Eloquent adapter against Storage\StorageInterface, or wrap the Doctrine one. Whatever you pick, it must persist the payment with its generated token — see Gotchas.

The checkout controller then looks like any Payum integration:

$gateway = app(GatewayRegistry::class)->getGateway('ems');
$payment = EmsPayment::create([
    'number'   => (string) Str::uuid(),
    'amount'   => $order->total_cents,
    'currency' => 'EUR',
]);
$storage->update($payment);

$token = $gateway->getTokenFactory()
    ->createCaptureToken('ems', $payment, 'payment.done');

return redirect($token->getTargetUrl());

Pattern C — bypass entirely. If justlease/payum-ems is a few hundred lines of request building and response mapping, read it and reimplement behind your own EmsClient. This removes Payum, the storage abstraction, and the abandoned-bridge risk in one move. Default to this unless you already have Payum in the stack.

Land the abstraction first. Whatever pattern you pick, put it behind an internal PaymentGateway interface (authorize, capture, refund, handleNotification) before writing the EMS adapter. Swapping acquirers later should not touch checkout or reconciliation code.

Callback flow. The bundle relies on Payum tokens for notification URLs. Generate the notify target from a stable, configured base URL — never from the incoming request host — and route it to a controller that hands the request to the gateway's Notify action, then transitions your own order state.

Gotchas and Tips

  • Not a Laravel package. If you install the -bundle package in Laravel and wonder why nothing registers, this is why. Use the underlying library.
  • Distribution is fragile. Bitbucket VCS repo, likely no Packagist, no visible license, no tags. Pin a commit SHA, mirror the repo internally, and get written confirmation you may fork before you build on it.
  • Zero stars, zero dependents, single vendor. Treat it as a reference implementation you own. There is no bug-report pipeline and no security cadence. Assign an owner and budget a periodic review against current EMS API docs.
  • Payum major drift. 1.x and 2.x differ in action wiring and namespaces. Check the constraint in composer.json; a mismatch produces confusing "action not found" errors at runtime rather than install time.
  • Token storage is the #1 failure mode. The notify callback has no session and no auth — it resolves the payment purely from the token in the URL. If your storage doesn't persist the Payment and its serialized details, the callback returns "payment not found" and the payment is orphaned. Test this explicitly by hitting the notify URL with a fresh process.
  • Callback verification is yours. The bundle hands the request to Payum's Notify action; it does not necessarily verify EMS's signature or source. Add signature/source checks in your controller before trusting the payload, and make the endpoint idempotent (EMS may retry).
  • Enumerate the supported surface before promising it. List the Action classes in payum-ems. If there's no refund or void action, you don't have refunds — the bundle won't invent them. Same for 3DS/SCA, tokenized repeat charges, and partial refunds, which are the things the assessment flags as unverified.
  • Debugging: log every outbound request and inbound response via a PSR HTTP client middleware (or Payum's HTTP client logger if configured). Payment integrations fail at the wire, and the default exception messages hide the payload. Persist the raw response on every state transition.
  • Extension points: subclass the GatewayFactory and append custom actions in create(); in Symfony, add them via a compiler pass. In Laravel, just mutate the gateway after construction. This is the safest way to add logging, retries, or idempotency keys without forking the actions.
  • Amount units. Verify whether the client expects integer cents or decimals before you ship — getting this wrong is silent and only surfaces in reconciliation.
  • Config keys don't match the README (there isn't one). DependencyInjection/Configuration.php is the source of truth; copy from it.
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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log