Bank Payments via Nello Pay for WooCommerce is a WooCommerce payment gateway for one-time bank payments through the hosted Nello Pay checkout of Neonomics AS, for stores in Norway (NOK), Sweden (SEK), Denmark (DKK) and Finland (EUR).
The customer chooses Pay by Bank, is redirected to Nello Pay, selects a bank, signs in there and approves an account-to-account payment. Nello Pay for WooCommerce keeps the server authoritative: an order is paid only when Nello Pay's authenticated webhook reports that the funds were received.
This repository contains the complete human-readable PHP, TypeScript and SCSS source plus the build and test tooling used to produce the WordPress.org release ZIP.
- Hosted Nello Pay checkout for one-time Pay by Bank payments; the store never sees bank credentials and ships no payment front end.
- WooCommerce Classic Checkout, Checkout Blocks and the order-pay page; guests and logged-in customers; HPOS on or off.
- Server-authoritative confirmation: the customer's return is navigation only; only
PAYMENT_COMPLETEDfrom the authenticated webhook pays an order. - Durable webhook inbox: every update is stored before it is acknowledged, deduplicated by content and applied by an explicit state machine (apply / no-op / stale / conflict).
- Duplicate-payment protection with a database mutex and a durable reservation per order.
- Payment attempt history: a payment through an earlier checkout page is assigned to the order or reported as a possible duplicate.
- No polling: Nello Pay has no status endpoint, so silence is handled with explicit time rules (abandoned checkouts, approvals that stay unconfirmed).
- No personal data sent to the provider; payer details reported by the provider are never stored.
- Exact amounts: decimal strings end to end, never binary floating point.
- Configuration health, connection test, the Nello Pay Health page, Site Health, alerts and structured redacted logs.
- WP-CLI for status, connection test, bank list, event processing and reconciliation.
- No bundled third-party library; reproducible release ZIP built from a strict allowlist.
| PHP | 8.1 – 8.4 |
| WordPress | 6.6 or newer |
| WooCommerce | 8.7 or newer |
| Database | MySQL 8.0 / 8.4 or MariaDB 10.11 / 11.4 |
| Store currency | NOK, SEK, DKK or EUR — the currency of the selected market |
| Nello Pay | a Merchant Portal account with a receiving account in that market |
| Site | publicly reachable over HTTPS (Nello Pay delivers webhooks over HTTPS only) |
- Install the release ZIP (Plugins → Add New → Upload) and activate it; WooCommerce must be active.
- Open WooCommerce → Settings → Payments → Nello Pay.
- Copy the API key from the Merchant Portal (Company settings → Integration). Sandbox and Production have separate keys.
- Choose the Market.
- Generate a webhook key, save, then register the webhook in the Merchant Portal
(Company settings → Webhook): the Webhook URL shown on the Nello Pay settings screen
(without
https://) and the same key. - Test connection, enable the method and place a Sandbox test order.
Sandbox outcome amounts: 20 → failed, 30 → cancelled, 40 → the bank stopped reporting, any
other amount → completed.
WooCommerce order
↓ process_payment(): order mutex + durable reservation
POST /api/v1/checkout-requests (Nello Pay Checkout API, API key)
↓ { id, redirectUrl }
customer → hosted Nello Pay checkout → bank login → approval
↓ ↘
customer returns to the store Nello Pay → webhook (shared key) for every status change
(navigation only, never evidence) ↓
authenticate → store → acknowledge → apply
↓
state machine → WooCommerce order
| Nello Pay status | Order |
|---|---|
STARTED, PAYMENT_CREATED |
Pending payment |
PAYMENT_INITIATED (approved) |
On hold |
PAYMENT_COMPLETED (funds received) |
paid: Processing / Completed |
PAYMENT_FAILED, FAILED |
Failed, payable again |
PAYMENT_CANCELLED, CANCELLED, TIMED_OUT |
payable again |
PAYMENT_NONTRACKABLE |
On hold; the merchant confirms or rejects the funds on the order |
Nello Pay has no refund API: a refund is a bank transfer recorded with WooCommerce's manual refund.
POST /wp-json/buckmerce-nellopay/v1/webhook, authenticated by the shared key in the api-key
header (constant-time comparison). Answers: 200 (stored), 401 (missing or wrong key), 413
(body over 64 KiB), 503 (no key configured, or the update could not be stored).
Without a webhook key the gateway is not offered: no payment could ever be confirmed.
- Amount and currency always come from the WooCommerce order on the server.
- The API key and the webhook key are never rendered, never sent to the browser and redacted from logs.
- The redirect target must be an HTTPS address on
neonomics.io. - Customer-facing status requests require the order key, order ownership and a nonce.
- Every admin action requires
manage_woocommerceand a nonce. - The webhook key cannot be removed while Production payments are open.
wp buckmerce-nellopay status # diagnostics report (no secrets)
wp buckmerce-nellopay test-connection # read-only API check
wp buckmerce-nellopay banks [--country=NO|SE|DK|FI]
wp buckmerce-nellopay process-events # apply stored webhook updates now
wp buckmerce-nellopay reconcile # one reconciliation passActions: buckmerce_nellopay_checkout_created, buckmerce_nellopay_payment_state_changed,
buckmerce_nellopay_payment_confirmed, buckmerce_nellopay_payment_failed,
buckmerce_nellopay_payment_cancelled, buckmerce_nellopay_payment_nontrackable,
buckmerce_nellopay_payment_manual_review, buckmerce_nellopay_webhook_processed.
Filters: buckmerce_nellopay_checkout_options (allowlisted optional checkout fields: receiving
account, creditor address, branding identifiers), buckmerce_nellopay_alert_recipient.
add_filter('buckmerce_nellopay_checkout_options', static function (array $options, WC_Order $order): array {
$options['creditorAccount'] = array('creditorName' => 'Example Shop AS', 'iban' => 'NO9386011117947');
return $options;
}, 10, 2);composer install # development tools only; nothing from vendor/ is shipped
npm ci
npm run build # Parcel: resources/ts + resources/scss → assets/Quality gates:
composer validate --strict && composer syntax && composer lint && composer stan && composer test
npm test
bash scripts/check-identity.sh && bash scripts/audit-source.sh && bash scripts/check-translations.shRelease ZIP and the suites that install only that ZIP on a disposable site:
npm run plugin-zip && bash scripts/verify-package.sh
bash scripts/test-package-smoke.sh
bash scripts/test-integration.sh # HPOS off and on, real parallel processes, translations, uninstall
bash scripts/test-plugin-check.sh
bash scripts/test-browser-e2e.sh # Classic + Blocks checkout, webhooks, admin, accessibility
npm run test:sandbox # real Nello Pay Sandbox (needs a Sandbox API key)Local inputs (database credentials, Sandbox key) go into a git-ignored .env; see .env.example.
Nello Pay for WooCommerce contacts the Nello Pay Checkout API (checkout.sandbox.neonomics.io /
checkout.neonomics.io) to create a payment and receives payment status webhooks from it. It
sends the order amount and currency, market and language, a payment message with the order
number, the store name, internal references and the return addresses — never the customer's name,
email address or postal address. Bank login happens at Nello Pay and the customer's bank.
One-time bank payments in one Nordic market per store. Not included: cards, subscriptions, saved payment methods, batch or scheduled payments, automatic refunds.
GPL-2.0-or-later. See LICENSE.