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

Adyen Bundle Laravel Package

sparkling/adyen-bundle

A Symfony bundle for integrating the Adyen payment platform, offering configuration and services to handle payments, notifications, and Adyen API interactions within Symfony applications.

View on GitHub
Deep Wiki
Context7

Getting Started

First, the reality check. sparkling/adyen-bundle is a Symfony 2 bundle, not a Laravel package. It ships a DependencyInjection extension, a config tree, and service YAML — things Laravel's container has no hook for. composer require sparkling/adyen-bundle on Laravel 10/11 will fail at resolution (Symfony ~2.x components, PHP ^5.3|^7.0 constraints). Do not plan on installing it. Plan on reading it.

Minimal steps that are actually worth doing:

  1. Clone the repo, don't require it. git clone https://github.com/ruudk/AdyenBundle into a scratch directory outside your project. Note the package name (sparkling/adyen-bundle) differs from the upstream repo (ruudk/AdyenBundle) — diff the Packagist dist against upstream before trusting either.
  2. Look here first, in this order:
    • Resources/config/services.* — the service IDs and injected constructor args tell you the entire public surface in one file.
    • DependencyInjection/Configuration.php — the config keys (merchant account, API key, test/live mode, skin code, HMAC key) are a ready-made checklist for your own config/adyen.php.
    • The service classes wrapping Adyen\Client / the payment API — usually a recurring-contract service and a notification/payment service. That's where all the domain logic lives, and it's perhaps 5–10 classes total.
  3. Enumerate the endpoints it hits. Grep for the Adyen library calls and write down every endpoint, request field, and response field. This inventory is the real deliverable of the read.
  4. Take that inventory to Adyen before writing code. The bundle targets the legacy recurring model (hosted payment page, RECURRING payment type, recurringDetailReference). Confirm those endpoints are still enabled for your merchant account and get a sunset date. This gate can kill the whole initiative and costs one email.
  5. First use case to port: the initial authorisation that creates a recurring contract. It's the one flow everything else hangs off, and it's small enough to validate the whole approach end to end in a day.

Implementation Patterns

Treat the repo as a specification artifact. The Symfony wiring is worthless to you; the recurring-billing domain shape is the asset. Lift the shape, write the code natively against adyen/php-api-library.

The contract lifecycle, as expressed by the bundle (this is the part worth copying verbatim into your domain model):

  1. Shopper pays once with recurring.contract = RECURRING → Adyen returns a recurringDetailReference.
  2. Persist shopperReference (your user ID, stable) plus the recurringDetailReference — one shopper can have many, so model a payment_methods table with a is_default flag, not a column on users.
  3. Merchant-initiated charges send selectedRecurringDetailReference + shopperReference + shopperInteraction: ContAuth, with no shopper present.
  4. Disable a contract when the customer removes a card — otherwise you'll keep a live reference to a cancelled instrument.

Laravel wiring pattern:

// app/Contracts/AdyenGateway.php — the only thing your app code should touch
interface AdyenGateway {
    public function authoriseRecurring(AuthoriseRequest $r): AuthoriseResult;
    public function chargeStored(ChargeRequest $r): ChargeResult;
    public function disableContract(string $shopperRef, string $detailRef): void;
}

Bind it in a AdyenServiceProvider reading config/adyen.php (typed config, env() only inside the config file). Bind a FakeAdyenGateway in testing so no test ever hits the network — the bundle can't give you this, and it's the single highest-value thing you'll add.

Webhook pattern: controller does one thing (verify HMAC over the raw body, return 200 immediately), then dispatches ProcessAdyenNotification on a queue. The job switches on eventCode and is idempotent on pspReference (unique index on a adyen_notifications table — insert-first, bail on duplicate). Adyen retries aggressively; without this you will double-fulfil orders.

Charge ledger pattern: every merchant-initiated charge gets an application-generated idempotency key (subscription_id:period_start) written before the HTTP call. The legacy recurring API plus naive retries is a well-documented path to charging a customer twice.

Interop pattern if a legacy Symfony app is still live: don't port. Dual-write recurringDetailReference into both systems during transition, route charges by a per-account feature flag, and reconcile contract state nightly until drift is zero. Then retire the old path — a strangler, not a rewrite.

Gotchas and Tips

  • The package name is a supply-chain smell. sparkling/adyen-bundle vs ruudk/AdyenBundle, zero dependents, archived. If you ever do vendor this code, diff the dist against upstream and pin the commit hash in repositories.
  • PHP 8 will break it silently, not loudly. Symfony 2.8's ceiling is PHP 7.0. Expect dynamic-property deprecations (fatal in 8.2+), removed functions, and old PHPUnit/Twig. If you fork, that's your first patch batch.
  • Response shape drift is the real failure mode. An unmaintained client that misparses a changed Adyen response fails quietly. Validate responses strictly and alert on unknown fields rather than passing them through.
  • Secrets. Symfony 2-era parameters.yml puts credentials uncomfortably close to VCS. When you reimplement, keep merchant account, API key, and HMAC key in .env → secrets manager, and never let the HMAC key into a log or an exception payload.
  • HMAC verification must run on the raw request body, before any middleware parses or re-encodes it. In Laravel, read $request->getContent() in the controller, not $request->all().
  • Redact before logging. Adyen request/response logging is essential for debugging and is also a PCI/PII hazard. Log the endpoint, pspReference, resultCode, and amounts — never the full card payload or the API key header.
  • Debug against Adyen's test merchant account, not mocks, for the first pass. Mock-based tests are what you build after you know the real response shapes; building them first just encodes your assumptions about a legacy API you haven't confirmed is live.
  • There are no useful extension points for you. The bundle's extensibility is a Symfony config tree and compiler passes, none of which exist in Laravel. The only extension point worth reproducing is the gateway interface plus a fake — everything else is a dead end.
  • Budget the maintenance, not the integration. The code is small (a payments-literate engineer reads it in a day). The cost is owning an unmaintained money-handling path forever. Fork it into an internal package only with a named owner and a plan for the next PHP upgrade; otherwise this becomes an unpatchable blocker the first time the platform moves.
  • Recommended path: official adyen/php-api-library + a thin Laravel wrapper of your own, with the lifecycle, ledger, and webhook patterns above. Use this repo for two days of reading, then add nothing to composer.json.
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
shitoudev/permissionmanager