Developer notes
Technical reference for developers who customize Vipps MobilePay Payments. Every endpoint, header, field and state with its official source is listed in Conformance.
Add-on identity
Section titled “Add-on identity”| Item | Value |
|---|---|
| Add-on id | kv_vipps_mobilepay |
| Function prefix | fn_kv_vipps_mobilepay_ |
| Language variables | kv_vipps_mobilepay.* |
| CSS scope | .kv-vipps-mobilepay |
| PHP namespace | Tygh\Addons\KvVippsMobilepay |
| Payment processor | Vipps MobilePay (script kv_vipps_mobilepay.php, registered on install, removed on uninstall) |
| Dispatches | backend kv_vipps_mobilepay.manage / connection / test_connection / register_webhook / log / log_csv / jobs / run_now / job_retry / job_discard / capture / refund / release / sync / cron; frontend kv_vipps_mobilepay.webhook, kv_vipps_mobilepay.cron; return payment_notification.return&payment=kv_vipps_mobilepay |
Structure
Section titled “Structure”| Class | Role |
|---|---|
Client\BaseClient |
HTTP (cURL, TLS verification, timeouts), JSON, access token cache (sealed), error mapping, masked logging |
Client\Api |
The ePayment, Webhooks and Access Token calls: createPayment, getPayment, capture, refund, cancel, webhooks, registerWebhook, deleteWebhook, ping; sends the common headers and the four Vipps-System-* headers (cscart, the CS-Cart version, plugin name kaviolabs-cscart-vipps, the add-on version) |
Client |
Client per account, the connection test |
Accounts, Secret |
Credentials per mode, sealed with AES-256-GCM (key derived from the store’s crypt key); one account per store owner (0) or per vendor |
Config |
Settings, owner mode, hosts, events, local brand, webhook address, cron key |
Access |
Who may see and manage which account, payment, order and job (vendors: own company only; money actions need the owner or the paying vendor) |
Money |
Minor units (ISO 4217 exponents), limits, reference and description formats, Idempotency-Key |
PaymentService |
Start, read-back (sync), apply (applyRemote), capture / refund / release, settle unanswered operations (resolve), webhook handling, cron, Multi-Vendor shares |
Transactions |
Payment rows, operations, locks per order / payment, shares of child orders, search |
Transition |
The state machine: API state and aggregate to local status; which statuses are open, settled or unpaid |
Webhook |
HMAC verification, header reading with the PHP-FPM fallbacks, signing (for tests) |
Idempotency |
Keys, named database locks (GET_LOCK, shop scoped), atomic claims |
Queue, Jobs, JobException |
Job queue with back-off 5 / 15 / 60 / 180 / 720 minutes; job types sync and refund; Jobs::schedule() runs the payment cron |
Log |
Event log with masking, filters, CSV, retention |
OrderTax, Upgrade\Synchronizer, License\Client |
Shared house components (tax shapes, self-healing upgrades, domain-bound license) |
Database tables
Section titled “Database tables”| Table | Purpose |
|---|---|
?:kv_vipps_mobilepay_accounts |
Credentials per company and mode (secrets sealed), webhook id / url / secret (sealed), cached token (sealed), last connection check |
?:kv_vipps_mobilepay_transactions |
One row per payment attempt: reference, Idempotency-Key, MSN, mode, status, state, currency, amount, stored order total, authorized / captured / refunded / cancelled amounts, flag, PSP reference, capture deadline |
?:kv_vipps_mobilepay_ops |
One row per capture, refund or release with its own Idempotency-Key, written before the call, with the aggregate value before the call (base_minor) |
?:kv_vipps_mobilepay_jobs |
Queue |
?:kv_vipps_mobilepay_log |
Log |
Hooks used
Section titled “Hooks used”PHP hooks (registered in init.php):
| Hook | Handler | Use |
|---|---|---|
change_order_status_post |
fn_kv_vipps_mobilepay_change_order_status_post |
Capture at the capture status, release at the release status, queue the refund at the refund status (a Multi-Vendor child order refunds its own share; the parent is skipped) |
prepare_checkout_payment_methods |
fn_kv_vipps_mobilepay_prepare_checkout_payment_methods |
Hides the method when there is no usable sales unit, no license, a currency or amount Vipps MobilePay cannot take, or a cart the sales unit mode cannot serve; sets the local brand name |
init_templater_post |
fn_kv_vipps_mobilepay_init_templater_post |
Only while the Upgrade Synchronizer is pending |
Template hooks (admin): orders:tabs_extra (the Vipps MobilePay tab), addons:manage and addons:tabs_content (license card), index:styles (CSS). The storefront payment template is views/orders/components/payments/kv_vipps_mobilepay.tpl of the responsive theme (inherited by Nova and bright_theme).
The order tab is prepared in controllers/backend/orders.post.php; the payment script payments/kv_vipps_mobilepay.php creates the payment and handles the return.
Behaviour worth knowing
Section titled “Behaviour worth knowing”PaymentService::sync()reads the payment (GET) andapplyRemote()applies it under the payment lock: AUTHORIZED is accepted only when the amount equals the attempt and the order total equals the stored one; otherwise the attempt is flaggedmismatchand released. A second approval of a paid order isduplicate; an approval for an order in the release status islate. Automatic actions run after the lock is released.- Payment start: an earlier attempt of the order is settled first (paid = success, open = cancelled with
cancelTransactionOnly). The row with reference and key is written beforePOST /epayment/v1/payments; no clear answer = lookup by reference, adopt, or resend with the same key. - Operations:
creatingtodone/failed/unknown. Before a resend the payment is read back; done = marked done; not done and younger than 24 hours = resent with its key; older = closed as not confirmed. - Locks:
GET_LOCKnames carry a hash of the database and the table prefix; the order lock is taken before the payment lock; the webhook waits at most 5 seconds (Vipps MobilePay waits 10). - Multi-Vendor owner mode: every lookup goes through
Transactions::payingOrderId()(child to parent); a child order refunds and captures only its share (Transactions::shareLeft()). - The webhook and cron dispatches are served by a front controller, are POST or secret-key requests and print no template, so the 4.21 full page cache never caches them.
- Vendor schema:
cron,run_nowandbackfillare admin only; every vendor-reachable action compares the company of the order, payment or job withruntime.company_id.
Test the HTTP layer without Vipps MobilePay
Section titled “Test the HTTP layer without Vipps MobilePay”The base URL can be overridden for tests in config.local.php (development only, loopback hosts only; an http:// return address is then allowed):
$config['kv_vipps_mobilepay_base_url'] = 'http://127.0.0.1:11981';node tests/mock-server/server.js 11981 starts a local stand-in of the ePayment, Webhooks and Access Token APIs built from the published specifications; node tests/e2e/e2e.mjs and node tests/e2e/vendor.mjs run the HTTP end-to-end tests against it; php81 tests/unit.php and php83 tests/unit.php run the unit tests. See tests/test-plan.md.
Template overrides
Section titled “Template overrides”Admin templates live in design/backend/templates/addons/kv_vipps_mobilepay/, the storefront payment template in the responsive theme. Do not edit them in a store; they are replaced on update.
Release-gate audit fixes (2026-11-07)
Section titled “Release-gate audit fixes (2026-11-07)”- The webhook answers within Vipps MobilePay’s 10 seconds: the read-back uses an 8 second HTTP timeout and 5 second lock waits; automatic capture / release and the settling of unanswered operations are stored as jobs (
after,sync) and run right after the answer (fastcgi_finish_request()where available) or by the cron. - Stop statuses: the release status and Declined (D). An order in a stop status is never revived by a late approval, its open payment is withdrawn, its reservation released, and manual capture is refused for stopped, failed and incomplete orders.
- Capture “at once” of a Multi-Vendor parent payment captures child by child (a stopped vendor order’s share is never captured) and releases the rest.
- Named locks are counted per request (
Idempotency::lock()), and the lock names include the database and the table prefix. - A payment is only handled with the sales unit (MSN) it was created on; changing the MSN of a mode with open or reserved payments is refused.
- Payment records survive an uninstall; the debug log masks
key=(the customer’s return key).