BazPay for Magento 2 and Adobe Commerce
Built for the stores Magento is actually used for: several websites, several currencies, a cache layer in front and a finance team that works in invoices and credit memos.
- TypeExtension
- Runs onOpen Source / Adobe Commerce 2.4.6+
- First installHalf a day
- Reviewed
Install with Composer
There is no zip and no admin uploader, deliberately. A Magento store has a deploy pipeline, and a payment extension that arrives outside it is an extension nobody can roll back.
# from the project root, in maintenance modecomposer require bazpay/module-paymentsbin/magento module:enable BazPay_Paymentsbin/magento setup:upgradebin/magento setup:di:compilebin/magento setup:static-content:deploy -fbin/magento cache:flush# confirm it is enabled and schema-currentbin/magento module:status BazPay_PaymentsModule is enabled On Adobe Commerce cloud, commit the composer.json and composer.lock changes and let the deploy hooks run setup:upgrade — do not run these by hand on an ephemeral node.
Then set the keys at Stores → Configuration → Sales → Payment Methods → BazPay. Start in test mode; the sandbox key pair is visible in the dashboard immediately after sign-up, without an approval step. The module writes its webhook endpoint into your BazPay account when you first save a valid secret key.
Pin an exact version rather than a caret range on production. We follow semantic versioning and the API is dated, but a payment path is the last place you want an unattended minor upgrade landing during a sale weekend.
Configuration scope
Every field the module exposes can be overridden at website or store-view level. This is the part worth planning before you start clicking, because the wrong choice at default scope quietly propagates to storefronts you did not mean to touch.
| Setting | Sensible scope | Why |
|---|---|---|
| API keys | Website | One legal entity per website is the common shape; store views share its keys. |
| Enabled methods | Store view | A Dutch view leads with iDEAL; a German one does not need it at all. |
| Statement descriptor | Store view | The shopper should recognise the brand they bought from, not the group name. |
| Payment action | Website | Capture policy is a finance decision, and it should not differ per language. |
| Debug logging | Default | You want it on or off everywhere while diagnosing, never in one view only. |
Method availability can be narrowed further by billing country, order total and customer group, so a wholesale group can be shown SEPA Direct Debit while retail sees cards and wallets. The full list of what can be enabled is on the method reference.
Invoices, captures, credit memos
Magento already has vocabulary for taking and returning money, and the module maps onto it rather than inventing a parallel one. Your finance team keeps working in the screens they know.
| In Magento | At the gateway | Notes |
|---|---|---|
| Order placed | Payment authorised | Funds reserved. Nothing has moved yet under Authorize. |
| Invoice, capture online | Capture | Partial invoices produce partial captures, one per invoice. |
| Invoice, capture offline | Nothing | Only correct when the money was already taken outside Magento. |
| Credit memo, refund online | Refund | Full or partial, unlimited count, up to the captured total. |
| Cancel order | Void the authorisation | Only possible before capture. After capture it is a refund. |
Under Authorize, the authorisation holds for seven days on cards and is voided automatically when it expires. Under Authorize and Capture, the invoice is created with the order. Bank methods such as iDEAL and BLIK are inherently capture-at-authorisation, so they invoice immediately whatever the setting says — the money has already moved and pretending otherwise would misstate the ledger.
Cron and reconciliation
Order state is driven by signed webhooks, so payments do not depend on cron. Cron is the safety net for the cases webhooks cannot cover on their own.
- Re-fetching events that arrived while the store was down or mid-deploy.
- Voiding authorisations that reached expiry without an invoice.
- Cancelling pending orders whose payment was abandoned at the bank.
- Writing the daily settlement reference onto captured transactions.
# is the reconciliation job running at all?bin/magento cron:run --group=bazpay# last ten runs, newest firstmysql -e "SELECT job_code, status, executed_at FROM cron_schedule WHERE job_code LIKE 'bazpay%' ORDER BY schedule_id DESC LIMIT 10"bazpay_reconcile success 2026-07-27 09:15:02bazpay_reconcile success 2026-07-27 09:00:01# rows stuck at 'pending' mean Magento cron is not running The job group is bazpay and it runs every fifteen minutes. Rows that stay pending mean Magento's own cron is not running, which will be breaking far more than payments.
Cache, indexers, inventory
Most Magento payment incidents are not payment bugs. They are a cache layer, an asynchronous indexer or an inventory reservation behaving exactly as documented, in a place nobody expected to matter.
Full-page cache
The webhook route must not be cached and must not require a session. Add
/bazpay/webhook to the pass list in Varnish or Fastly, and exclude it from any
bot-protection rule that challenges unknown user agents — our sender will not solve a
JavaScript challenge, and a challenged webhook is a webhook that never arrives.
Asynchronous order grid
With sales_grid_async_indexing enabled, the sales grid trails the actual order
state by an indexer run. An order can be paid, invoiced and correct while the grid still
shows it as pending. Check the order view, not the grid, when verifying a payment.
Inventory reservations
Multi-source inventory places a reservation when the order is created and releases it if the payment fails. A store that cancels pending orders manually, rather than letting the module's cron job do it, will slowly leak reservations and show stock that is not really committed.
Diagnostics
Turn on debug logging in the module configuration and reproduce the order. Every request and
response is written to var/log/bazpay.log with the request id, and card data is
redacted before it is written — the log is safe to attach to a support ticket.
| Symptom | Usually | Fix |
|---|---|---|
| BazPay missing from checkout | Config set at the wrong scope | Switch the scope selector to the store view and check it is enabled there. |
| Payment succeeds, order stays pending | Webhook cached or challenged | Pass /bazpay/webhook through Varnish and the WAF. |
| Method list ignores a change | Config cache | bin/magento cache:clean config after every scope change. |
| Refund button does nothing | Offline credit memo chosen | Use Refund, not Refund Offline. |
| Class not found after deploy | Stale compiled DI | Re-run setup:di:compile; the module ships plugins and factories. |
For the wire-level detail — signature verification, the retry ladder, replaying an event by hand — see the webhooks guide. For forcing a specific decline while you test the unhappy paths, sandbox behaviour lists the cards that produce each reason code on demand.
Common questions
- Does the extension work on Adobe Commerce as well as Open Source?
- The same package serves both from 2.4.6 upward, including Adobe Commerce on cloud infrastructure. Cloud projects install it as an ordinary Composer dependency and deploy it through the normal pipeline; nothing needs to be uploaded through an admin screen.
- Can different store views take different payment methods?
- Yes, and this is the main reason merchants choose Magento in the first place. Every setting the module exposes can be overridden at website or store-view scope, so a German view can show cards and SEPA while a Dutch one leads with iDEAL, each with its own descriptor on the shopper's statement.
- Do we have to run Magento cron for payments to work?
- Payments succeed without it, because order state is driven by webhooks. Cron handles the safety net: reconciling any event that was missed while the store was unreachable, expiring stale authorisations and cleaning up abandoned pending orders. A store with no cron will eventually accumulate orders that never resolve.
- How does the module handle a store with several currencies?
- We charge in the currency the order was placed in, not the base currency. The presented amount, the authorised amount and the settled amount are therefore the same number, which is what keeps the reconciliation file matching the sales report without a manual conversion step.
- Is the source available for review before we install it?
- Yes. The package is source-available to merchants using it, so your team can read it, run it through a static analyser and pin a version in composer.json like any other dependency. Nothing is obfuscated and there is no phone-home beyond the API calls the payment itself requires.
Somewhere else to be
Cart plugins
- WooCommerce Plugin Block checkout and the classic shortcode, HPOS-ready, refunds from the order screen and a REST webhook route.
- PrestaShop Module Installed from the back office, worked from the order screen. Credit slips, custom order states and multistore keys.
- Shopware Plugin Rule Builder decides which methods appear, the state machine records what happened, Flow Builder reacts to it.
- OpenCart Extension A deliberately small build for small catalogues. Hosted fields, status mapping, and a short list of things it does not do.
Continue
Not sure this is the right route?
Send the platform, the version and the markets you sell into. An engineer answers with the plugin, the API path or an honest "not yet" — not a discovery call.