concept24 / omnipay-ingwebpay
ING WebPay (ING Bank România) driver for the Omnipay payment processing library
Requires
- php: ^8.2
- omnipay/common: ^3.2
Requires (Dev)
- php-http/guzzle7-adapter: ^1.0
- phpunit/phpunit: ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
ING WebPay (ING Bank România) driver for the Omnipay payment processing library, REST API mpi/rest.
Requirements
- PHP 8.2+ (Laravel 12 and 13 compatible — the only dependency is
omnipay/common3.x) - an HTTP client for Omnipay, e.g.
php-http/guzzle7-adapter
Installation
composer require concept24/omnipay-ingwebpay
Usage
use Omnipay\Omnipay;
$gateway = Omnipay::create('IngWebPay'); // or new \Omnipay\IngWebPay\Gateway
$gateway->initialize([
'userName' => '…', // API user from ING
'password' => '…',
'testMode' => true, // securepay-uat.ing.ro; false → securepay.ing.ro
]);
// 1. register the payment and send the client to ING
$response = $gateway->purchase([
'amount' => '122.89',
'currency' => 'RON', // RON (946) or EUR (978); default RON
'returnUrl' => 'https://shop.ro/ing/return',
'description' => 'Order C24-77',
'language' => 'ro', // ro / en
// 'transactionId' => 'C24-77', // → orderNumber, only if ING configured your account to receive it
// 'email' => 'client@example.com',
])->send();
if ($response->isRedirect()) {
$orderId = $response->getTransactionReference(); // keep it with the payment: ING's mdOrder
$response->redirect(); // GET to formUrl; ING gives the client 10 minutes
} else {
$response->getMessage(); // ING error (errorCode in getCode())
}
// 2. on returnUrl ING adds ?orderId=…
$status = $gateway->completePurchase()->send(); // reads orderId from the current request
// 3. later, for clients who never came back (ING sends no server notification)
$status = $gateway->fetchTransaction(['transactionReference' => $orderId])->send();
Statuses (getOrderStatusExtended.do)
getOrderStatus() (constants on StatusResponse) | ING | Response |
|---|---|---|
| 0 | registered, not paid | isPending() |
| 1 | pre-authorized | isSuccessful() |
| 2 | paid | isSuccessful() |
| 3 | authorization reversed (cancelled before settlement) | isCancelled() |
| 4 | refunded — ING's test environment reports it also after a partial refund | isRefunded() |
| 5 | 3-D Secure in progress at the issuer | isPending() |
| 6 | declined — also when the 10-minute payment session expires (getActionCode() -2007, Session time limit) | isDeclined() |
| 7 | partially refunded (code of the processing platform; not seen from ING) | isRefunded() |
null | unknown order / ING error | none |
getMessage() gives the bank's answer for the card (e.g. Wrong expiry date.), getActionCode() its code, getTransactionId() ING's orderNumber, getAmountInteger() the amount in bani, getDate() when the order was registered.
Card details, once the client entered a card: getCardMask() (466286**6040), getCardholderName(), getCardExpiry() (YYYYMM), getApprovalCode() (approved payments only).
ING does not notify the merchant's server. Its integration requirements: check the status when the client returns, and automatically about 10 minutes after registration for the clients who don't.
Pre-authorization
$gateway->authorize([...same as purchase...])->send(); // registerPreAuth.do
$gateway->capture(['transactionReference' => $orderId])->send(); // deposit.do — no amount = full amount
$gateway->capture(['transactionReference' => $orderId, 'amount' => '50.00'])->send();
$gateway->void(['transactionReference' => $orderId])->send(); // reverse.do (same day, before 22:00)
Refund
$gateway->refund(['transactionReference' => $orderId, 'amount' => '122.89'])->send(); // refund.do — full or partial
Several partial refunds are allowed up to the paid amount. After any refund, full or partial, ING reports the order with status 4; getOrderStatusExtended.do does not say how much was refunded (only ING's short getOrderStatus.do shows the remaining depositAmount). An order that isn't paid answers errorCode 7 (Refund is impossible for current transaction state).
deposit.do, reverse.do and refund.do need extra rights requested from ING; without them, the same operations are done from the ING WebPay console.
Not supported by ING's API
ING sends no server-to-server notification (no webhook/IPN), has no transaction list method, and saved cards cannot be charged through the API (paymentOrderBinding.do is not available). Google Pay and Apple Pay appear on ING's payment page without any integration work.
Tests
composer install
vendor/bin/phpunit # unit tests, no network
ING_USER=… ING_PASS=… vendor/bin/phpunit --group uat # against ING's test environment
On ING's test payment page (securepay-uat.ing.ro), card 4662861119116040, any future expiry and CVV 203 gives an approved payment; another CVV is declined. 3-D Secure: "Confirmare autentificare". The test API user and password come from ING with the merchant's test access.
License
MIT — see LICENSE.
Changelog
- unreleased — documents that ING reports status 4 also after a partial refund (checked on ING's test environment).
- 1.0.2 — status 4 is a full refund (
StatusResponse::REFUNDED,isRefunded()), not a cancellation; status 7 (partial refund) added;isCancelled()now means status 3 only.StatusResponse::REVERSEDstays as a deprecated alias ofREFUNDED. - 1.0.0 — first release.