You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Eupago's backoffice takes a single notification URL per channel and sends every payment method's Realtime 1.0 notification to it, but each per-method route only looked for the reference in its own table. A merchant taking more than one method only got confirmations for the method whose URL was set.
A single GET /eupago/callback endpoint picks the handler from mp (PC:PT, MW:PT, PS:PT, PF:PT, CC:PT, now a PaymentMethod enum).
The per-method routes are deprecated aliases of it, to be removed in v4. Each falls back to its own method when mp is unknown, so a URL already set in the backoffice confirms every method after the upgrade.
The callback routes no longer run the web middleware group, which started a session storing the URL, chave_api included.
The channel and API key are checked before any other rule, so a caller without them no longer learns which references exist.
Marking a reference as paid locks its row and fires the event after the commit, so simultaneous deliveries fire it once and queued listeners always find the payment stored. A redelivered notification gets a 200 without firing the event again.
Multibanco references with an amount range or repeat payments can now be confirmed. Each payment is recorded in a new mb_reference_payments table, backfilled for references paid since v3.9.0, and passed to MBReferencePaid as $payment.
The docs and UPGRADE.md cover the new endpoint, custom route mounts, the event timing and range payments.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🟡 Changes recommended
The shared confirmPayment() helper can return an incorrect 404 under concurrent duplicate deliveries due to an out-of-transaction idempotency check combined with a state = 0 locked lookup.
This PR updates EuPago Realtime 1.0 webhook handling so merchants can configure a single notification URL per channel (as required by Eupago’s backoffice) while still confirming all payment methods, improving security (no web sessions; validate caller first) and reliability (idempotent acknowledgements; post-commit event dispatch).
Changes:
Add a single /eupago/callback endpoint that dispatches to the correct handler based on mp, and keep per-method endpoints as deprecated aliases.
Refactor callback processing to validate channel/API key first and to make confirmations idempotent (avoid re-firing events on redelivery).
Add Multibanco payment recording via a new mb_reference_payments table/model and extend MBReferencePaid to include the specific payment.
File
Description
UPGRADE.md
Documents the new unified callback endpoint, deprecations, and migration steps.
tests/Pest.php
Updates test helpers to use new mp codes and default MB ranges.
tests/Feature/RoutesDisabledTest.php
Asserts unified callback route is not registered when routes are disabled.
tests/Feature/PackageBootTest.php
Asserts unified callback route is registered by default.
The reason will be displayed to describe this comment to others. Learn more.
Copilot review overview
🔵 Needs a closer look
Callback validation still allows non-numeric valor values that can trigger database errors during numeric comparisons, and the upgrade docs’ custom per-method route example omits the route default needed to preserve the promised fallback behavior.
valor is only validated as required, but it is later used in numeric SQL comparisons (e.g. MbReference::accepting() uses min_value <= valor <= max_value). If a valid caller sends a non-numeric value (or an array), this can cause a database error (notably on PostgreSQL) instead of a clean 422 response. Consider validating valor as numeric to ensure predictable behavior.
Set default_payment_method in per-method route example
UPGRADE.md:64
The custom per-method route example does not set a default_payment_method. Without that route default, CallbackController will reject callbacks where mp is missing or uses an unknown/legacy code (the package’s built-in deprecated aliases explicitly set this default). Updating the snippet keeps behavior consistent with the deprecated per-method endpoints.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Eupago's backoffice takes a single notification URL per channel and sends every payment method's Realtime 1.0 notification to it, but each per-method route only looked for the reference in its own table. A merchant taking more than one method only got confirmations for the method whose URL was set.
GET /eupago/callbackendpoint picks the handler frommp(PC:PT,MW:PT,PS:PT,PF:PT,CC:PT, now aPaymentMethodenum).mpis unknown, so a URL already set in the backoffice confirms every method after the upgrade.webmiddleware group, which started a session storing the URL,chave_apiincluded.mb_reference_paymentstable, backfilled for references paid since v3.9.0, and passed toMBReferencePaidas$payment.Fixes
This fixes #94.