LokiCheckout_Opayo
Opayo by Elavon card payments for the Loki Checkout on Magento 2.4.x, using the Elavon Payment Gateway (EPG) REST API and its Hosted Payment Fields.
The card fields (name, number, expiry, security code) are iframes served by Elavon. Card data is entered on Elavon's infrastructure only; Magento never receives, logs or stores card numbers, expiry dates or security codes. 3-D Secure runs inside the Elavon frames as well.
Opayo's legacy Pi API (
pi-*.sagepay.com) has been retired in favour of the Elavon Payment Gateway. Earlier versions of this module used Pi; this version is a rewrite on top of EPG. The module name, Composer package and payment method code (lokicheckout_opayo) are unchanged.
Requirements
- Magento Open Source / Adobe Commerce 2.4.x
- PHP 8.2+
loki-checkout/magento2-core^2.0 (the Loki Checkout)- An Elavon Payment Gateway account with an API key (merchant alias + secret key)
- Optional:
magento/module-cspfor Content-Security-Policy whitelisting
Installation
composer require loki-checkout/magento2-opayo bin/magento module:enable LokiCheckout_Opayo bin/magento setup:upgrade bin/magento setup:di:compile bin/magento cache:clean
Configuration
Stores → Configuration → Sales → Payment Methods → Opayo by Elavon (Loki Checkout)
| Field | Notes |
|-------|-------|
| Enabled | Turns the method on. |
| Title | Shown in the checkout. |
| Environment | Sandbox or Production. |
| Region | Production only: Europe (*.eu.elavonpayments.com) or North America (*.na.elavonpayments.com). |
| Merchant Alias | The merchant alias of your EPG API key. |
| Secret Key | The secret key (sk_…) of your EPG API key. Stored encrypted. |
| Payment Action | Authorize Only (capture when invoicing) or Authorize and Capture. |
| 3-D Secure Enabled | Requests 3-D Secure for every payment session. |
| Debug Logging | Writes masked request/response logs to var/log/lokicheckout_opayo.log. |
| API Connection / Request Timeout | Seconds; defaults 10 / 30. |
| New Order Status, Sort Order, Applicable Countries, Min/Max Order Total | Standard payment method options. |
The public key (pk_…), processor account id and gateway merchant id of the EPG
account are not needed.
| Environment | API | Hosted fields |
|-------------|-----|---------------|
| Sandbox | https://api.sandbox.elavonpayments.com | https://hpp.sandbox.elavonpayments.com |
| Production EU | https://api.eu.elavonpayments.com | https://hpp.eu.elavonpayments.com |
| Production NA | https://api.na.elavonpayments.com | https://hpp.na.elavonpayments.com |
Checkout flow
- When the payment method is shown, the browser calls
POST lokicheckout_opayo/session/create. Magento creates an EPG order from the quote totals and a payment session (hppType: hostedPaymentFields,doCreateTransaction: true,doCaptureaccording to the payment action,doThreeDSecureaccording to the configuration). The session reference is kept in the server-side checkout session and reused while it is valid. - The Elavon Hosted Fields SDK renders the card fields in iframes.
- On Place Order, the fields are validated (
getState()). The browser then callsPOST lokicheckout_opayo/session/prepare: Magento creates a fresh EPG order with the current quote totals and attaches it to the session, so the charged amount is always determined server side. - The hosted fields are submitted with the billing/shipping address and e-mail. Elavon performs 3-D Secure and creates the transaction. A decline is shown in the checkout; when Elavon allows it, the shopper can retry with another card (otherwise a new session is started).
- The order is placed. The authorize (or capture, for authorize-and-capture) command loads the transaction through the session stored on the payment and verifies it: it must be authorized, for exactly the order total and currency, and for the order's increment id. Only then is the order created.
Both session endpoints require a valid form key, are rate limited and return only checkout-safe JSON.
Admin flows
| Magento action | EPG call |
|----------------|----------|
| Invoice (capture online) | POST /transactions/{id} with {"doCapture": true} (full amount) |
| Credit memo (refund online) | POST /transactions with type: refund and the parent transaction (partial refunds supported) |
| Void | POST /transactions with type: void and the parent transaction |
| Cancel order | Same as void; a transaction that can no longer be voided does not block the cancellation (the failure is logged) |
Partial capture is not supported (can_capture_partial is off).
Content Security Policy
etc/csp_whitelist.xml allows the hosted fields hosts (hpp.sandbox, hpp.eu,
hpp.na) for script-src and frame-src.
Security considerations
- Card data is only entered in Elavon iframes (minimal PCI scope).
- The browser never decides the amount or which transaction belongs to the order: the session is stored server side and the transaction is verified (state, amount, currency, order reference) before the order is placed.
- Placing the same order twice does not charge twice: a session that already holds a successful transaction for the current totals is not submitted again.
- EPG ids are validated before they are used in API paths, and requests always go to the configured API host.
- Logs are masked: secret key, Authorization header, card tokens, fingerprints and 3-D Secure authentication values never end up in a log file.
Logging
var/log/lokicheckout_opayo.log. Errors are always logged (masked); request and
response details only with Debug Logging enabled.
Testing
Unit tests (no credentials needed):
cd dev/tests/unit ../../../vendor/bin/phpunit -c phpunit.xml.dist ../../../vendor/loki-checkout/magento2-opayo/Test/Unit
Integration tests: Test/Integration.
Playwright tests run real payments against the EPG sandbox; see
Test/Playwright/README.md.
Troubleshooting
- "Unable to initialize card payment." — check the merchant alias, secret key,
environment and region; with Debug Logging on,
var/log/lokicheckout_opayo.logshows the EPG response (e.g.401 unauthorized). - Card fields do not appear — check the browser console for CSP violations on the
hpp.*.elavonpayments.comhosts. - "The card payment does not match the order total." — the quote changed between submitting the card and placing the order; the shopper can simply place the order again.
Known limitations
- No stored cards (vault), wallets (Apple Pay / Google Pay) or partial capture yet.
- 3-D Secure challenges are handled by Elavon's frames; the sandbox test cards only cover frictionless 3-D Secure.
Current status
@dev
to the composer command.
Support
For getting support, create an Issue under the following project URL:
https://gitlab.yireo.com/loki-checkout/LokiCheckout_Opayo.git
Configuration Options
The following options of this module can be configured via the Store Configuration:
Loki Components
The following LokiComponents are created or references in this module:
loki-checkout.payment.methods.lokicheckout_opayo.form
Module Dependencies
The following dependencies are declared in the module its `etc/module.xml` file:
LokiCheckout_Core
Loki_Base
Loki_Components
Loki_CssUtils
Loki_FieldComponents
Loki_MapComponents
Magento_Backend
Magento_Catalog
Magento_Checkout
Magento_CheckoutAgreements
Magento_Config
Magento_Customer
Magento_Directory
Magento_Eav
Magento_Newsletter
Magento_Payment
Magento_Quote
Magento_Sales
Magento_Shipping
Magento_Store
Magento_Tax
Magento_Vault
Yireo_CspUtilities
Composer details
LokiCheckout_Opayoloki-checkout/magento2-opayo
ext-json: *
ext-pcre: *
loki-checkout/magento2-core: ^2.0
magento/framework: ^103.0
magento/module-checkout: ^100.0
magento/module-directory: ^100.0
magento/module-payment: ^100.0
magento/module-quote: ^101.0
magento/module-sales: ^103.0
magento/module-store: ^101.0
php: >=8.2 <8.6
loki/magento2-components: ^2.8
loki/magento2-css-utils: ^1.0
magento/module-backend: ^102.0
magento/module-config: ^101.0
monolog/monolog: ^2.0 | ^3.0
psr/log: ^1.0 | ^2.0 | ^3.0
Releases
Changelog
Changed
- Rebuilt on the Elavon Payment Gateway (EPG) with Hosted Payment Fields, replacing the
retired Opayo Pi API (
pi-*.sagepay.com). Configuration now uses a merchant alias and secret key (plus a region for production) instead of a vendor name and integration key/password. - 3-D Secure is handled inside the Elavon hosted fields; the 3-D Secure challenge controllers and page were removed.
- The transaction is verified server side (state, amount, currency, order reference) before the order is placed.
Removed
- Merchant Session Key web API and controller,
sagepay.js, the transaction reconciliation cron and its configuration.
Fixed
- The secret key was decrypted twice, because Magento already decrypts values declared
with the Encrypted backend model in
etc/config.xml.