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

sylius/payum-bundle

Sylius PayumBundle integrates the Payum payment abstraction with Sylius, enabling configurable payment gateways, secure capture and authorization workflows, and seamless checkout payment processing for Symfony-based e-commerce stores.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the honest part: you cannot composer require sylius/payum-bundle into a Laravel app and get anything usable. It is a Symfony bundle with hard dependencies on Sylius\Bundle\ResourceBundle, Sylius\Bundle\CoreBundle, and the Sylius DI container. There is no service provider, no publishable config, no facade. It arrives in a project the only way it is meant to: transitively, as part of sylius/sylius. As a Laravel developer your first move is to decide which of these you are actually doing:

  1. You're standing up Sylius (separate Symfony deployable, likely behind an API/queue boundary). Then the bundle is already installed — skip to the config files below.
  2. You're staying in Laravel and need multi-gateway payments. Use payum/payum core directly, or vendor SDKs / Cashier / Omnipay. Use this bundle as a reference implementation for the patterns (gateway factories, token lifecycle, encrypted credentials, payment state machine), not as a dependency.

If you're in a Sylius app, look here first:

  • config/packages/sylius_payum.yaml — the sylius_payum.gateways tree. This is where every gateway lives.
  • Sylius\Bundle\PayumBundle\DependencyInjection\Configuration — the authoritative schema for gateway config and GatewayFactory names.
  • src/Sylius/Bundle/PayumBundle/Payum/Action/ — the authorize/capture/refund/status actions that drive the payment state machine.
  • The PaymentMethod admin form (PayumGatewayConfigType), which is where a gateway name gets bound to a Sylius payment method and its encrypted credentials.
  • debug:container for payum, payum.gateway_factory, and the sylius.payment state machine.

First use case to get working end to end: add the offline gateway to a payment method, run a checkout, and watch the payment transition from cart → new → processing → completed via the state machine. That proves config wiring, storage, and the state machine without touching a PSP. Then add a sandboxed Stripe or PayPal gateway and repeat.

Implementation Patterns

Config-first gateway registration. Define gateways under sylius_payum.gateways.<name> with a factory and payum options. A PaymentMethod then references that gateway by name, and the gateway config (API keys, sandbox flags) is stored encrypted on the GatewayConfig entity — not in YAML. This is the day-to-day pattern: YAML declares which kind of gateway, admin/DB holds the credentials per channel.

Payment method → gateway mapping. Sylius's GatewayConfig is keyed by factory name + config, and each PaymentMethod points at one. Multi-channel and multi-store falls out naturally: different channels get different PaymentMethod records pointing at different gateway configs. If you're rebuilding this in Laravel, that is the entity model to copy — credentials as a separate encrypted record, referenced by a payment method, not inlined into an order.

Custom gateway factories for uncovered PSPs. This is the extension point you'll actually use. Implement Payum\Core\GatewayFactory (extend AbstractGatewayFactory), register it with the payum.gateway_factory tag, and define the action pipeline (CaptureAction, NotifyAction, etc.). Do not fork the bundle or patch Sylius — the read-only repo means your patch will be erased on the next composer update. Own your factory in your own bundle.

Deferred capture. Auth-then-capture is the flow this bundle was shaped around: authorize on checkout, capture from the admin or a queue worker. The pattern is a command/console invocation of $gateway->execute(new Capture($token)) driven by an order-management action. In a Laravel-first org, replicate that with a queued job and an explicit state column — do not do capture inline in a request.

Webhook / notify handling. Payum issues token-based URLs (capture, notify, status) rather than Laravel-style signed routes. The pattern is: the PSP redirects to a Payum-generated URL containing a token, the token resolves back to a stored payment, and NotifyAction advances the state. Treat these as idempotent and order-agnostic — webhooks replay and arrive out of order. Verify by replaying the same notification twice and confirming no double state transition.

Storage. Payum's StorageInterface is implemented against Sylius entities via Doctrine. If you ever port this to Eloquent, that interface is the seam: implement it over your payments and payment_tokens tables, and keep token rows append-only.

Testing. Use the gateway's sandbox credentials plus a small console command that executes a Capture/Refund on a fake token. This is the fastest way to debug a wedged payment without clicking through checkout. Sylius's sylius.behat payment contexts cover the happy path; add explicit tests for refund and partial refund — those are where state machine bugs hide.

Gotchas and Tips

  • Never pin sylius/payum-bundle independently. It's a read-only subtree split of the Sylius monorepo. Pin sylius/sylius and let this track it; independent pinning causes version drift against core and you will debug a class that isn't the one loading.
  • The 11 stars and 0 dependents are a packaging artifact. Dependents aren't counted for transitive installs. Don't read the low numbers as abandonment — and don't read them as health either. The real support surface is the Sylius monorepo's Slack and issue tracker.
  • Read-only means zero independent release cadence. There are no PRs here, no issue tracker, no security releases outside a Sylius core release. Your security patches arrive on Sylius's train. Plan Sylius major upgrades (roughly annual) as payment-relevant events.
  • Payum's mental model is the real onboarding cost. gateway → factory → action → request/reply → token → storage is steep, and fewer engineers know it than know Laravel. Budget for one person to become the Payum owner; you will need them at 2 a.m.
  • Credential encryption is a landmine. Gateway configs are encrypted at rest with Sylius's encryption key. Losing or rotating that key without a re-encryption path leaves GatewayConfig unreadable and payments failing in ways that look like PSP errors. Prove rotation in staging before go-live.
  • Token URLs break behind a proxy. Payum generates absolute capture/notify URLs from the request context. Wrong trusted-proxy or host config gives you localhost URLs sent to the PSP — checkouts that hang at "waiting for payment" with no obvious error. Verify generated URLs from the CLI and from behind the load balancer.
  • "Processing" is where stuck payments live. When a payment wedges, inspect the stored token and the Sylius payment state in the DB before touching code — nine times out of ten it's a provider response the action didn't map, not a state machine bug. debug:container --tag=payum.gateway_factory confirms your factory is registered; debug:container payum confirms the gateway is built.
  • 3DS2/SCA is the thing to validate before committing. Payum's model predates much of PSD2. Spike your primary PSP's 3DS2 behavior on your target Sylius version first — if it doesn't hold, you own that work.
  • Payum is transitional. Sylius is moving to its own PaymentRequest abstraction. If this is a multi-year build, write the migration into your upgrade plan now while the codebase is small, and keep your PSP-specific logic isolated in your own gateway factories so the eventual swap is a small diff.
  • The offline gateway is underrated. For invoice/B2B flows it removes an entire PSP integration from v1 scope. Start there.
  • If you're in Laravel, stop. Everything valuable here is either (a) Payum core, which is framework-agnostic and installable, or (b) patterns worth reading. There is no glue that makes this bundle work without Sylius, and any hybrid must be two deployables over HTTP/queue — never a shared autoloader.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle