mageme / module-eu-withdrawal
mageme/module-eu-withdrawal
Magento 2 implementation scaffolding for the EU consumer-withdrawal workflow under Art. 11a Directive 2011/83/EU (as amended by 2023/2673): guided storefront flow (find order, select items, confirm), durable-medium receipt email, 22-locale Annex I content. NOT legal advice — see README disclaimer; merchant is responsible for compliance verification.
MageMe EU Withdrawal for Magento 2
EU withdrawal button for Magento 2 — the consumer right-of-withdrawal flow
required by 19 June 2026 under Article 11a of the
Consumer Rights Directive (2011/83/EU) as amended
by Directive (EU) 2023/2673.
The Magento 2 withdrawal button your EU storefront needs before the 19 June 2026 deadline — a storefront-ready, guided flow (find order → select items → review & confirm) with durable-medium receipt emails and Annex I content in 22 EU locales, on Luma, Hyvä, and Breeze.
It adds only the legal withdrawal step required under Art. 11a, and works alongside your existing RMA / refund process rather than replacing it.
Documentation · Get Pro features

What it does
- Storefront withdrawal flow — guided form (find order → select items → review & confirm) for guests and registered customers at
/withdraw-contract/ - Annex I in 22 EU locales — verbatim EUR-Lex translations where available, theme-overridable per locale
- Durable-medium receipt — confirmation email with a frozen snapshot of the legal text shown to the consumer
- Admin grid and workflow — filterable request list, mass actions, status state machine, CSV export
- Article 16 exclusions — preset list configurable per category, with merchant override
Screenshots
Storefront — guided withdrawal flow (find order → select items → review & confirm):

Admin — manage withdrawal requests (status workflow, jurisdictions, refund totals, CSV export):

Durable-medium receipt email — the confirmation sent to the consumer with a frozen snapshot of the legal text they accepted. (The SHA-256 integrity-hash card and one-click verification shown here are a Pro add-on.)

Free vs Pro
| Feature | Free | Pro |
|---|---|---|
| Storefront withdrawal flow | Yes | Yes |
| Annex I — 22 EU locales | Yes | Yes |
| Durable-medium receipt email | Yes | Yes |
| Admin grid + status workflow | Yes | Yes |
| Article 16 exclusion presets | Yes | Yes |
| Receipt verification — SHA-256 cryptographic audit | — | Yes |
| Annex I forensic snapshot — immutable per-request copy | — | Yes |
| Hash-chain audit log — DB-backed, tamper-evident | — | Yes |
| Magic-link guest access — one-click tokenised URL | — | Yes |
| Seal-photo evidence — optional intact-seal photos | — | Yes |
Install
composer require mageme/module-eu-withdrawal
bin/magento module:enable MageMe_EUWithdrawal
bin/magento setup:upgrade
bin/magento cache:flush
After installation, enable the module at Stores → Configuration → MageMe Extensions → EU Withdrawal.
→ Full installation guide and configuration reference
On Luma and Breeze (Swissup) storefronts the base module works out of the box — no extra package required. Only Hyvä themes need the companion module below.
Hyvä storefront
If your storefront runs on a Hyvä theme, install the theme companion alongside this module — it ports the
customer-facing withdrawal flow and order-view integrations to Tailwind + Alpine.js:
composer require mageme/module-eu-withdrawal-hyva
bin/magento module:enable Hyva_MageMeEUWithdrawal
bin/magento setup:upgrade
If you also run Hyvä Checkout, add the checkout companion as well — it re-implements the pre-contract Annex I block
and the digital-content waiver step (Art. 16(m)) for Hyvä Checkout's Magewire runtime:
composer require mageme/module-eu-withdrawal-hyva-checkout
bin/magento module:enable Hyva_MageMeEUWithdrawalCheckout
bin/magento setup:upgrade
→ Hyvä theme companion · Hyvä Checkout companion
Requirements
- Magento 2.4.4 – 2.4.9 (Open Source / Commerce)
- PHP 8.1, 8.2, 8.3, 8.4, or 8.5 — match your Magento version's PHP support matrix
- MySQL 8.0+ / MariaDB 10.6+
Legal disclaimer
This module is provided AS-IS, without warranty. It is a technical implementation of the workflow described in
Article 11a of Directive 2011/83/EU; it is not legal advice and has
not been reviewed by EU consumer-law counsel.
The merchant is solely responsible for verifying that this implementation satisfies their jurisdiction's specific
consumer-protection requirements, reviewing bundled translations for accuracy in their target markets, and adapting
Article 16 exclusion presets to their actual catalogue.
Streaming and SaaS subscriptions — out of scope
This module's Art. 16(m) waiver flow is for one-time digital content — extensions, ebooks, courses, software
licences, downloadable templates. It is not for ongoing digital services (streaming, SaaS subscriptions),
where the waiver may not remove the withdrawal right — a digital-content vs digital-service distinction now before the
CJEU in Case C-234/25. For subscription cancellations and
pro-rata refunds, use your billing platform's own cancellation flow.
→ Full disclaimer and merchant compliance checklist
Digital-content waiver on API / headless orders
The Art. 16(m) waiver record is created only from a genuine storefront
confirmation (the customer ticking both consent boxes). By default, digital-content orders placed through the
REST/GraphQL API are blocked unless a genuine consent record exists for each digital item (the same protection
the storefront enforces). If your headless integration collects the consent itself, record it through the
waiver-event mechanism and the order will pass; or set Stores → Configuration → MageMe Extensions →
EU Withdrawal → Digital Waiver → Enforce Waiver on API / Headless Orders to No to opt out of API enforcement
(the storefront waiver step is unaffected either way).
Custom Magento development
Need a feature an extension doesn't cover, or a bespoke Magento build? MageMe takes on custom extension development and integration work.
Support
- Documentation: docs.mageme.com
- Bug reports and feature requests: GitHub Issues
Note: This GitHub Issues tracker is for free tier bug reports and feature requests only.
Changelog
See CHANGELOG.md. This module follows Semantic Versioning.
License
All tiers are governed by the MageMe End User License Agreement (mageme.com/license).
The base module is distributed free of charge; Pro requires a paid commercial licence.
MageMe builds Magento 2 and Adobe Commerce extensions for B2B merchants — form building, quoting, catalog control, and EU compliance.
1.0.7
- New: Restrict by Customer Group - optionally hide the self-service withdrawal flow from selected customer groups (e.g. your B2B / wholesale groups), while guests and consumers keep it
- New: a new "If delivery is never confirmed" setting decides whether orders that reached a delivered status without a recorded delivery date stay open or are treated as not eligible (default)
- New: Statuses Excluded From Withdrawal - choose order statuses (such as a legacy import status) that should never be offered for withdrawal
- New: submitting a withdrawal request now adds a note with the requested refund to the related order's timeline
- Fix: the refund amount shown in the order-timeline notes and the durable-medium receipt now reflects the full amount instead of the shipping portion only
- Other: the checkout pre-contractual withdrawal information now follows the country and customer-group scope, so it shows only where the self-service withdrawal applies
1.0.6
- New: the withdrawal-CTA order and shipment emails can now be selected directly from the Sales Emails template dropdown - no need to clone a template first
- New: approving, denying or cancelling a request now adds a short note to the related order's timeline (refund amount, denial reason, or who cancelled), so the outcome is visible on the order itself
- New: a drop-in "Withdraw from contract" link block for custom themes, so the link can be placed anywhere in the storefront
- Fix: status emails now send guests to the withdrawal page instead of a login page they cannot use
- Fix: the "Show Footer Link" setting now hides the storefront footer link when it is turned off
- Fix: the withdrawal form no longer errors on themes that do not include the optional photo-evidence step
- Other: the submission notification email now lists all of its available variables in the admin template editor
1.0.5
- New: Item Selection setting - the withdrawal form can run in "Full order" mode where the request always covers all returnable items
- New: Extension points for the Pro photo evidence step on the withdrawal form
- New: Country Scope setting - optionally limit the self-service withdrawal flow to customers in selected countries
- Fix: final confirmation button now renders the legally required "Confirm withdrawal" label in the customer's language instead of "Submit return request"
- Fix: request creation no longer fails when a third-party extension dispatches the request-created event without eligibility data
- Fix: the "Withdraw from contract" link in order and shipment emails now renders when the email is resent from the admin or sent by a background job
- Fix: an order now stays available for withdrawal through the whole of its final eligible day
- Fix: a logged-in customer opening a withdrawal link for an order that is not their own is now turned away
- Other: Removed the redundant Eligibility column from the items table on the admin withdrawal request page.
1.0.4
- Fix: The digital-content waiver step no longer fails to save when the billing address is set during checkout.
- Other: Removed a non-functional Privacy & Retention settings group.
- Other: Internal cleanup, dead-code removal and a more robust order-lookup rate limiter.
- Other: Module permissions now appear under the Sales section in admin role permissions (thanks to Ole Schäfer).
1.0.3
- Fix: The refund total now matches the order total when a payment-method discount, gift card or other order-level adjustment applies — such orders previously could not be withdrawn or showed an inflated refund.
- Fix: The refund total shown right after submitting a withdrawal now includes the shipping refund.
- Fix: Corrected the German translation of the "Withdraw from contract" label.
1.0.2
- New: Digital-content detection can now recognise digital items inside bundle products.
- Fix: Submission confirmation email and the merchant copy now also send for requests made through the storefront app.
- Fix: The store logo now appears in withdrawal emails.
- Fix: Email USP and social icons now display in Gmail, Outlook and Yahoo.
- Fix: Withdrawal emails are sent in the store's language instead of always English.
- Other: Storefront-app submissions now go through the same rate-limiting and audit logging as the form.
1.0.1
- New: "Show more" in the order picker — load more eligible orders on demand.
- Fix: Order picker lists newest orders first.
- Fix: Order picker honours a withdrawal period over 14 days.
- Fix: Delivered date is consistent between the order list and detail.
- Fix: Admin request view no longer crashes in the free edition.
1.0.0
- New: First public release. EU right-of-withdrawal management for Magento 2 — a guided customer withdrawal flow (find order, pick items, review, submit), eligibility rules, automatic refund calculation, and durable-medium receipt emails.
- New: Admin request management — withdrawal request grid, request detail screen, approve/deny workflow, and configurable withdrawal period and return address.
- New: Pre-contractual Annex I information notice on checkout, plus a downloadable model withdrawal form (Art. 6(1)(h)).
- New: Digital-content waiver step with express consent and loss-of-right acknowledgement (Art. 16(m)).
- New: Merchant alert email on each new request, and a "Withdraw from contract" call-to-action in order and shipment confirmation emails.
- New: Translations for 22 EU locales.
| Version | Stability | QA Status | Compatibility | Released |
|---|---|---|---|---|
| 1.0.7 | stable | Fail | Magento 2.4.7-2.4.9 Details | 2026-06-21 22:28:43 |
| 1.0.6 | stable | Not tested | Not yet tested Details | 2026-06-18 16:49:31 |
| 1.0.5 | stable | Not tested | Not yet tested Details | 2026-06-17 12:51:04 |
| 1.0.4 | stable | Not tested | Not yet tested Details | 2026-06-11 16:58:14 |
| 1.0.3 | stable | Not tested | Not yet tested Details | 2026-06-08 20:20:01 |
| 1.0.2 | stable | Not tested | Not yet tested Details | 2026-06-04 18:45:17 |
| 1.0.1 | stable | Not tested | Not yet tested Details | 2026-06-03 19:53:20 |
| 1.0.0 | stable | Not tested | Not yet tested Details | 2026-06-01 18:43:39 |
Requires 2
| Package | Constraint |
|---|---|
| mageme/module-core | ^2.0 |
| php | ~8.1.0||~8.2.0||~8.3.0||~8.4.0||~8.5.0 |
Compatibility
Each Magento release line is installed on its supported PHP versions, then the module is built (DI compilation + static-content deploy) and its unit and integration suites are run. The matrix shows the lines and PHP versions the module is confirmed to install and run on. Code-quality results further down (phpstan, phpcs, …) are reported separately and never affect compatibility.
Code Quality
Advisory checks against the module's source. Static analysis runs once across the whole module; PHPStan re-runs per Magento + PHP version because resolvable symbols differ between releases. These NEVER affect the Compatibility badge — a phpcs finding can't make a module incompatible.
Static analysis
Coding standards (phpcs), mess detection (phpmd), copy-pasted code (cpd), PHP cross-version compatibility, composer.json validity. Each runs once for the whole module.
| Tool | Status | Findings | Summary |
|---|---|---|---|
| PHPCS | Fail | 348 | 1 error, 347 warnings (ruleset: Magento2) — 39 auto-fixable with phpcbf |
| PHPMD | Warning | 142 | 142 rule violations (MissingImport:62, NPathComplexity:20, UnusedFormalParameter:18, CyclomaticComplexity:16, ExcessiveClassComplexity:8) |
| Cpd | Warning | 2 | 2 duplicated chunks spanning 82 total lines (min-lines=5, min-tokens=70) |
| Composer validate | Info | 1 | valid; 1 advisory note (composer validate --strict) |
PHPStan
Type-checks the module's PHP against a real Magento install at the configured gate level. Re-runs per Magento and PHP version because resolvable symbols differ between releases. Cell → details modal.
Tests
Unit and integration suites, run for each applicable Magento and PHP version. A test failure speaks to the module's behaviour, not its compatibility with a Magento line, so it is reported here separately and never reddens the compatibility matrix.
Unit tests
| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | ||
| 2.4.8 | N/A | N/A | ||
| 2.4.9 | N/A | N/A |
Integration tests
| Magento | PHP 8.2 | PHP 8.3 | PHP 8.4 | PHP 8.5 |
|---|---|---|---|---|
| 2.4.7 | N/A | N/A | ||
| 2.4.8 | N/A | N/A | ||
| 2.4.9 | N/A | N/A |
Security
Security checks run directly against the module: an audit of its declared dependencies for known vulnerabilities (composer audit) and a scan of its source for malware and web-shell signatures. Each runs once. A malware detection fails the version outright.
More from mageme
View vendorZapier integration add-on for WebForms Pro 3
Zoho integration add-on for WebForms Pro 3
Freshdesk integration add-on for WebForms Pro 3
Mailchimp integration add-on for WebForms Pro 3
Turn an existing module into recurring revenue.
If you already maintain a Magento 2 module on GitHub or GitLab, listing it on Packagento takes about five minutes. We mirror your tags, handle distribution signing, and route paid licenses through Stripe Connect, so you can keep shipping the way you already do.