Version: 1.19 January 2024
Contact e-mail address: contact@smartpay.rabobank.nl
© Rabobank, 2024
No part of this publication may be reproduced in any form by print, photo print, microfilm or any other means without written permission by Rabobank.
Disclaimer: This manual is exclusively intended for third parties who take care of the technical link between Rabo OmniKassa and the customer's webshop for and on behalf of clients. Rabobank is not liable for possible damage resulting from errors in or incorrect use of the manual. For example, but not limited to, damage that occurs because the technical link between Rabo OmniKassa and the customer's webshop does not work (completely) correctly. Rabobank has the right to change this manual.
- Changelog
- Requirements and installation instructions
- Introduction
- Steps in processing payments
- Customer pays order
- Receive updates about orders
- Request available payment brands
- Request available iDEAL issuers
- Added User-Agent and partnerReference documentation
- Added shopperBankStatement documentation
- Added new endpoints to support refunds
- Removed Afterpay from supported paymentbrands
- Added support for Java 17.
- Added section on retrieval of iDEAL issuers.
- Added section on improving customer experience using payment brand parameters.
- Documented new property
fullName
of CustomerInformation. - Updated supported .NET versions.
- Various minor corrections and improvements.
Install the package through Composer. Edit your project's composer.json
file by adding:
{
"require": {
"rabobank/omnikassa-sdk": "*"
}
}
Next run the Composer update command from the terminal:
composer update
Then include the composer-generated autoloader.php file in your code using:
require __DIR__ . '/vendor/autoload.php';
If you are using the Java SDK, you should have Java Runtime Environment version 1.8, 11 or 17 available. To use the Java SDK, extract the ZIP file to the system on which the webshop is installed. The actual SDK is a single jar and is located in the SDK subdirectory. The jar files that this SDK depends on are in the Lib subdirectory. Both the SDK jar file and the dependent jar files should be included in the classpath to be able to use the Java SDK.
The .NET SDK supports the following .NET platforms:
- .NET Framework (version 4.6.2 or higher)
- .NET 6.0
You can install the .NET SDK from NuGet https://www.nuget.org/packages/OmniKassa_Rabobank/
If applicable, this document will display separate code examples for these platforms.
In order to establish a HTTPS connection with Rabo OmniKassa, the Java Runtime environment, .NET environment or PHP (depending on the chosen SDK) should be configured with a CA bundle so that the certificate of https://betalen.rabobank.nl can be validated. Normally this is already the case and you do not need to do anything. If you are running PHP under Windows, you may need to configure the php.ini to include the property openssl.cafile containing the path to the CA bundle. Consult the PHP documentation for more information.
This document describes how a webshop can be connected to Rabo OmniKassa using the available SDKs. At this moment Rabobank SDKs provides the following programming languages/platforms: PHP, Java and .NET. It is possible that this manual already includes functionality that belongs to a payment method that is not yet available in the Rabo OmniKassa dashboard, this is not a problem for the proper operation of the SDK. In the Rabo OmniKassa Dashboard, the available payment methods can be selected.
In the code, the identifiers {refresh_token} and {signing_key} refer to the refresh token and the signing key respectively. These indications should not be taken literally but replaced with the values you find in the dashboard of Rabo OmniKassa 2.0.
In the code the identifiers {userAgent} and {partnerReference} refer to the User-Agent and the partnerReference you want to add to the order announcement. Both are set when creating an endpoint.
- User-Agent: The userAgent field is filled with the name and version of your application. It should adhere to the standard described here.
- partnerReference: The partnerReference field can be used to send us your partnerReference, which we provided. Please consult with your Smart Pay Account manager first before using this field.
In order to obtain a global picture, this chapter describes the steps in which a payment is made via Rabo OmniKassa. In the remaining chapters each of these steps is described in more detail.
Each payment consists of the following three steps:
- Order announcement Before the customer can meet the payment request, the webshop first announces the order at Rabo OmniKassa. The order will include all the information that Rabo OmniKassa needs to lead the customer through the payment steps. In a successful order announcement Rabo OmniKassa returns a unique ID identifying the order and an URL that points to the payment pages.
- Customer pays the order The webshop redirects the customer to the URL that Rabo OmniKassa returned to in the step above. The customer is directed to Rabo OmniKassa payment pages and can fulfill the payment request. When this is done, the customer is redirected back to the webshop.
- Receive Updates about orders In this step, Rabo OmniKassa sends a notification to the webhook URL of the webshop when one or more orders have been processed. By using a unique token (key) in this notification, the webshop can request the final status of these orders from Rabo OmniKassa. This step is optional and will only run if the webhook URL is configured in the Rabo OmniKassa dashboard.
The following chapters describe how these steps are implemented using the SDK.
In order to make a payment request, an order must first be prepared. The order contains all the information about the payment request that Rabo OmniKassa needs in order to guide the customer through the payment steps. The following code blocks are examples for creating an order. The order is subject to requirements and if it does not meet certain criteria, certain payment methods are not available, the order will be cleaned or rejected.
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\Money;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\OrderItem;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\PaymentBrand;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\PaymentBrandForce;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\PaymentBrandMetaData;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\ProductType;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\request\MerchantOrder;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\Address;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\CustomerInformation;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\VatCategory;
$orderItems = [OrderItem::createFrom([
'id' => '1',
'name' => 'Test product',
'description' => 'Description',
'quantity' => 1,
'amount' => Money::fromDecimal('EUR', 99.99),
'tax' => Money::fromDecimal('EUR', 21.00),
'category' => ProductType::DIGITAL,
'vatCategory' => VatCategory::HIGH
])];
$shippingDetail = Address::createFrom([
'firstName' => 'Jan',
'middleName' => 'van',
'lastName' => 'Veen',
'street' => 'Voorbeeldstraat',
'postalCode' => '1234AB',
'city' => 'Haarlem',
'countryCode' => 'NL',
'houseNumber' => '5',
'houseNumberAddition' => 'a'
]);
$billingDetails = Address::createFrom([
'firstName' => 'Jan',
'middleName' => 'van',
'lastName' => 'Veen',
'street' => 'Factuurstraat',
'postalCode' => '2314BA',
'city' => 'Haarlem',
'countryCode' => 'NL',
'houseNumber' => '15'
]);
$customerInformation = CustomerInformation::createFrom([
'emailAddress' => 'jan.van.veen@gmail.com',
'dateOfBirth' => '20-03-1987',
'gender' => 'M',
'initials' => 'J.M.',
'telephoneNumber' => '0204971111',
'fullName' => 'Jan van Veen'
]);
$order = MerchantOrder::createFrom([
'merchantOrderId' => '100',
'shopperBankstatementReference' => '100'
'description' => 'Order ID: 100',
'orderItems' => $orderItems,
'amount' => Money::fromDecimal('EUR', 99.99),
'shippingDetail' => $shippingDetail,
'billingDetail' => $billingDetail,
'customerInformation' => $customerInformation,
'language' => 'NL',
'merchantReturnURL' => 'http://localhost/',
'skipHppResultPage' => true,
'paymentBrand' => PaymentBrand::IDEAL,
'paymentBrandForce' => PaymentBrandForce::FORCE_ONCE,
'paymentBrandMetaData' => PaymentBrandMetaData::createFrom([
'issuerId' => 'RABONL2U',
])
]);
Java
import java.util.Collections;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.*;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.order_details.*;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.enums.*;
OrderItem orderItem = new OrderItem.Builder()
.withId("1")
.withQuantity(1)
.withName("Test product")
.withDescription("Description")
.withAmount(Money.fromEuros(EUR, new BigDecimal("99.99")))
.withTax(Money.fromEuros(EUR, new BigDecimal("21.00")))
.withItemCategory(ItemCategory.DIGITAL)
.withVatCategory(VatCategory.HIGH)
.build();
CustomerInformation customerInformation = new CustomerInformation.Builder()
.withTelephoneNumber("0204971111")
.withInitials("J.M.")
.withGender("M")
.withEmailAddress("jan.van.veen@gmail.com")
.withDateOfBirth("20-03-1987")
.withFullName("Jan van Veen")
.build();
Address shippingDetails = new Address.Builder()
.withFirstName("Jan")
.withMiddleName("van")
.withLastName("Veen")
.withStreet("Voorbeeldstraat")
.withHouseNumber("5")
.withHouseNumberAddition("a")
.withPostalCode("1234AB")
.withCity("Haarlem")
.withCountryCode(CountryCode.NL)
.build()
Address billingDetails = new Address.Builder()
.withFirstName("Jan")
.withMiddleName("van")
.withLastName("Veen")
.withStreet("Factuurstraat")
.withHouseNumber("5")
.withHouseNumberAddition("a")
.withPostalCode("1234AB")
.withCity("Haarlem")
.withCountryCode(CountryCode.NL)
.build()
MerchantOrder order = new MerchantOrder.Builder()
.withMerchantOrderId("ORDID123")
.withShopperBankstatementReference("ORDER1234")
.withDescription("An example description")
.withOrderItems(Collections.singletonList(orderItem))
.withAmount(Money.fromEuros(Currency.EUR, new BigDecimal("99.99")))
.withCustomerInformation(customerInformation)
.withShippingDetail(shippingDetails)
.withBillingDetail(billingDetails)
.withLanguage(Language.NL)
.withMerchantReturnURL("http://localhost/")
.withSkipHppResultPage(true)
.withPaymentBrand(PaymentBrand.IDEAL)
.withPaymentBrandForce(PaymentBrandForce.FORCE_ONCE)
.withPaymentBrandMetaData(Collections.singletonMap("issuerId", "RABONL2U"))
.build();
.NET
using System.Collections.Generic;
using OmniKassa.Model;
using OmniKassa.Model.Enums;
using OmniKassa.Model.Order;
OrderItem orderItem = new OrderItem.Builder()
.WithId("1")
.WithQuantity(1)
.WithName("Test product")
.WithDescription("Description")
.WithAmount(Money.FromEuros(Currency.EUR, 99.99m))
.WithTax(Money.FromEuros(Currency.EUR, 21.00m))
.WithItemCategory(ItemCategory.PHYSICAL)
.WithVatCategory(VatCategory.LOW)
.Build();
CustomerInformation customerInformation = new CustomerInformation.Builder()
.WithTelephoneNumber("0204971111")
.WithInitials("J.M.")
.WithGender(Gender.M)
.WithEmailAddress("jan.van.veen@gmail.com")
.WithDateOfBirth("20-03-1987")
.WithFullName("Jan van Veen")
.Build();
Address shippingDetails = new Address.Builder()
.WithFirstName("Jan")
.WithMiddleName("van")
.WithLastName("Veen")
.WithStreet("Voorbeeldstraat")
.WithHouseNumber("5")
.WithHouseNumberAddition("a")
.WithPostalCode("1234AB")
.WithCity("Haarlem")
.WithCountryCode(CountryCode.NL)
.Build();
Address billingDetails = new Address.Builder()
.WithFirstName("Jan")
.WithMiddleName("van")
.WithLastName("Veen")
.WithStreet("Factuurstraat")
.WithHouseNumber("5")
.WithHouseNumberAddition("a")
.WithPostalCode("1234AB")
.WithCity("Haarlem")
.WithCountryCode(CountryCode.NL)
.Build();
Dictionary<string, string> paymentBrandMetaData = new Dictionary<string, string>();
paymentBrandMetaData.Add("issuerId", "RABONL2U");
MerchantOrder order = new MerchantOrder.Builder()
.WithMerchantOrderId("ORDID123")
.WithShopperBankstatementReference("ORDER1234")
.WithDescription("An example description")
.WithOrderItems(new List<OrderItem>() { orderItem })
.WithAmount(Money.FromEuros(Currency.EUR, 99.99m))
.WithCustomerInformation(customerInformation)
.WithShippingDetail(shippingDetails)
.WithBillingDetail(billingDetails)
.WithLanguage(Language.NL)
.WithMerchantReturnURL("http://localhost/")
.WithSkipHppResultPage(true)
.WithPaymentBrand(PaymentBrand.IDEAL)
.WithPaymentBrandForce(PaymentBrandForce.FORCE_ALWAYS)
.WithPaymentBrandMetaData(paymentBrandMetaData)
.Build();
Below are all the fields with the name, a description, and the rules to which the value of the field must comply.
MerchantOrder
Field | Description | Rules |
---|---|---|
merchantOrderId |
The identity of the order | Required |
if a shopperBankstatementReference is added: - May consist of all ASCII characters - This field is shortened to a maximum of 255 characters. |
||
if a shopperBankstatementReference is not added: - May consist only of alphanumeric characters - This field is shortened to a maximum of 24 characters. |
||
shopperBankstatementReference |
The reference to the order a consumer will find on their bankstatement | Optional |
May consist only of alphanumeric characters | ||
This field is shortened to a maximum of 24 characters. | ||
description |
A description of the order | Optional |
This field is shortened to a maximum of 35 characters. | ||
orderItems |
All items that will be ordered by the customer | Optional |
A maximum of 99 items may be supplied | ||
amount |
The total order amount in cents, including VAT | Required |
The amount must not exceed 99,999.99 | ||
The amount must be equal to the sum of all order items of the piece price (including VAT) multiplied by the number of copies. | ||
Due to the way VAT is calculated, rounding differences can prevent them from being equal. | ||
We therefore recommend that you base the total VAT amount on the VAT of the item price instead of the total order amount excluding VAT. | ||
For example: Suppose the price of an order item (excluding VAT) is €12.98 and a vat rate of 21% is used. When a customer order 7 copies, the price including VAT €12.98 + 21% = €15.71 is completed. The total order amount (including VAT) that is given in this field is 7 x €15.71 = €109.97. | ||
Note If the amount is not equal to the sum of the amounts of the order items then | ||
1. The order items are filtered from the order announcement | ||
shippingDetails |
The delivery address of this order | Optional |
language |
The texts on the payment pages will be in this language | Optional, the default value is EN. |
ISO 3166-1 Alpha-2, limited to NL, EN, FR and DE. | ||
If an unknown value is used: then EN will be used. | ||
merchantReturnURL |
The URL the customer will return to after the payment steps have been completed | Required |
Must be a valid URL | ||
paymentBrand |
The payment method to which the customer is limited | Optional |
Must be one of the following values: IDEAL, PAYPAL, MASTERCARD, VISA, BANCONTACT, MAESTRO, V_PAY, SOFORT | ||
When value is CARDS, then all card payment methods are offered (MasterCard, Visa, Bancontact, Maestro, and V PAY) | ||
paymentBrandForce |
Is used to enforce the payment method | Optional, if the field paymentBrand is supplied then this field is required. |
Must be one of the following values: FORCE_ONCE or FORCE_ALWAYS | ||
paymentBrandMetaData |
Additional parameters specific to the supplied payment method | Optional, when this field is supplied then the fields paymentBrand and paymentBrandForce must be set as well. |
The value of this field is a key-value map of strings. | ||
customerInformation |
A limited set of customer information | Optional |
billingDetails |
The billing address of this order | Optional |
initiatingParty |
An ID identifying the party from which the order announcement was initiated | Optional. This field must be left empty unless agreed otherwise with Rabobank |
skipHppResultPage |
Use this field to skip the hosted result page (also referred to as the success/thank you page) in the payment process | Optional |
For more information on how to use the paymentBrand
, paymentBrandForce
, paymentBrandMetaData
and the
skipHppResultPage
please consult
Improve customer experience using payment brand parameters.
Money
Field | Description | Rules |
---|---|---|
currency |
The currency | should not be null |
Must be EUR | ||
Other currencies are not supported | ||
amount |
The amount | should not be null |
Must be a natural number |
To create a Money instance, use the following code:
PHP
//1,75 Euro
$moneyFromCents = Money::fromCents('EUR', 175);
//75,99 Euro
$moneyFromDecimal = Money::fromDecimal('EUR', 75.99);
//Rounding examples
//1000 Euro cents
$amountInCents = Money::fromDecimal('EUR', 9.999)->getAmount();
//999 Euro cents
$amountInCents = Money::fromDecimal('EUR', 9.991)->getAmount();
//1000 Euro cents
$amountInCents = Money::fromDecimal('EUR',9.995)->getAmount();
Java
//1,75 Euro
Money moneyFromEuros = Money.fromEuros(Currency.EUR, BigDecimal.valueOf(175, 2));
Money moneyFromString = Money.fromEuros(Currency.EUR, new BigDecimal("1.75"));
.NET
using OmniKassa.Model;
using OmniKassa.Model.Enums;
Money moneyFromDecimal = Money.FromEuros(Currency.EUR, 1.75m);
Address / ShippingDetails
Field | Description | Rules |
---|---|---|
firstName |
customer's name | Required |
Has a maximum length of 50 Characters | ||
middleName |
customer's middle name | Optional |
Has a maximum length of 20 Characters | ||
lastName |
Last name of the customer | Required |
Has a maximum length of 50 Characters | ||
street |
Street name of the address | Required |
Has a maximum length of 100 Characters. | ||
Note: In the case of card payment at Worldline, this field is shortened to a maximum of 50 characters. | ||
postalCode |
Postal Code of the address | Required |
Must match the ZIP/Postal code format of the selected CountryCode | ||
city |
City of Address | Required |
Has a maximum length of 40 Characters | ||
countryCode |
Country Code of Address | Required |
Must be one of the following values: | ||
AF, AX,AL, DZ, VI, AS, AD, AO, AI, AQ, AG, AR, AM, AW, AU, AZ, BS, BH, BD, BB, BE,,BZ, BJ, BM, BT, BO, BQ, | ||
BA, BW, BV, BR, VG, IO, BN, BG, BF, BI, KH, CA, CF, CL, CN, CX, CC, CO, KM , CG, CD, CK, CR, CU, CW, CY, DK, | ||
DJ, DM, DO, DE, EC,,EG, SV, GQ, ER, EE, ET, FO, FK, FJ, PH, FI, FR, TF, GF, PF, GA, GM, GE, GH,,GI, GD, GR, | ||
GL, GP, GU, GT, GG, GN, GW, GY, HT, HM, HN , HU, HK, IE, IS, IN,,ID, IQ, IR, IL, IT, CI, JM, JP, YE, you, JO, | ||
KY, CV, CM, KZ, KE, KG, KI, UM,,KW, HR, LA, LS, LV, LB, LR, LY, LI, LT, LU, MO, MK, MG, MW, MV, MY, ML, MT, IM, | ||
MA, MH , MQ, MR, MU, YT, MX, FM, MD, MC, MN, ME, MS, MZ, MM, NA, NR, NL,,NP, NI, NC, NZ, NE, NG, NU, MP, KP, NO, | ||
NF, UG, UA, UZ, OM, AT, TL, PK, PW, PS, PA, PG, PY, PE, PN, PL, PT, PR, QA, RE , RO, RU, RW, BL, KN, LC, PM, VC, | ||
SB, WS, SM, SA, ST, SN, RS, SC, SL, SG, SH, MF, SX, SI, SK, SD, SO, ES, SJ, LK, SR, SZ, SY, TJ, TW, TZ, TH, TG, TK, | ||
TO, TT, TD, CZ, TN, TR, TM, TC, TV ,,UY, VU, VA, VE, AE, US, GB, VN, WF, EH, BY, ZM, ZW, ZA, GS, KR, SS, SE, CH | ||
houseNumber |
House number of the address | Optional |
Has a maximum length of 100 characters. | ||
Note: In the case of card payment at Worldline, this field is shortened to a maximum of 50 characters. | ||
houseNumberAddition |
House number addition of the address | Optional |
Has a maximum length of 6 characters |
The supported ZIP code formats are as follows. The remaining country codes only have a maximum length of 10 and are indicated in the table below as 'Other'.
Country code | Format | Maximum length |
---|---|---|
BE | \p{Digit} + | 4 |
DE | \p{Digit} + | 5 |
NL | \p{Digit}{4}\p{Alpha}{2} | 6 |
Other | N/a. | 10 |
CustomerInformation
Field | Description | Rules |
---|---|---|
emailAddress |
The email address of the customer | Optional |
Must be a valid email address | ||
Has a maximum length of 45 characters. | ||
dateOfBirth |
The date of birth of the customer | Optional |
Must be in the format: DD-MM-YYYY | ||
gender |
customer Sex | Optional |
Must be one of the following values: M, F | ||
initials |
customer Initials | Optional |
May consist only of alphabet characters | ||
Has a maximum length of 256 characters. | ||
telephoneNumber |
The telephone number of the customer | Optional |
May consist of numbers and alphabet characters | ||
Has a maximum length of 31 characters. | ||
fullName |
The full name of the customer | Optional |
Has a maximum length of 128 characters. | ||
Consult this section for more information. |
OrderItem
Field | Description | Rules |
---|---|---|
id |
The ID of the item | Optional |
Has a maximum length of 25 Characters | ||
name |
Name of the item | Required |
May consist only of alphabet characters | ||
Has a maximum length of 50 Characters | ||
description |
A description of the item | Optional |
Has a maximum length of 100 Characters | ||
quantity |
Number of copies | Required |
Must be a natural number greater than 0 | ||
amount |
The amount per piece in cents, including VAT | Should not be null |
tax |
VAT per piece in cents | Optional |
category |
Category of this item | Should not be null |
Must be one of the following values: | ||
DIGITAL, PHYSICAL | ||
vatCategory |
VAT Category of the item | Optional |
Must be one of the following values: | ||
The values refer to the different rates used in the Netherlands: | ||
1, 2, 3, 4 | ||
1 = high 21% | ||
2 = low (9%) | ||
3 = zero (0%) | ||
4 = none (exempt from VAT) |
The quantity describes how much the customer wants to have the of a particular product, for example 2 apples, or 3 pears. The amount indicates how much one product costs, so 1 apple costs €1.50, or 1 pear costs €1.75, and includes VAT.
If we detail the examples then it becomes:
PHP
$apples = OrderItem::createFrom([
'id' => '1',
'name' => 'Apple',
'description' => 'A delicious apple',
'quantity' => 1,
'amount' => Money::fromDecimal('EUR', 1.50),
'tax' => Money::fromDecimal('EUR', 0.14),
'category' => ProductType::PHYSICAL,
'vatCategory' => VatCategory::LOW
]);
$pears = OrderItem::createFrom([
'id' => '2',
'name' => 'Pear',
'description' => 'A delicious pear',
'quantity' => 3,
'amount' => Money::fromDecimal('EUR', 1.75),
'tax' => Money::fromDecimal('EUR', 0.16),
'category' => ProductType::PHYSICAL,
'vatCategory' => VatCategory::LOW
]);
Java
OrderItem apples = new OrderItem.Builder()
.withId("1")
.withQuantity(2)
.withName("Apple")
.withDescription("A delicious apple")
.withAmount(Money.fromEuros(Currency.EUR, new BigDecimal("1.50")))
.withTax(Money.fromEuros(Currency.EUR, new BigDecimal("0.14")))
.withItemCategory(ItemCategory.PHYSICAL)
.withVatCategory(VatCategory.LOW)
.build();
OrderItem pears = new OrderItem.Builder()
.withId("2")
.withQuantity(3)
.withName("Pear")
.withDescription("A delicious pear")
.withAmount(Money.fromEuros(Currency.EUR, new BigDecimal("1.75")))
.withTax(Money.fromEuros(Currency.EUR, new BigDecimal("0.16")))
.withItemCategory(ItemCategory.PHYSICAL)
.withVatCategory(VatCategory.LOW)
.build();
.NET
OrderItem apples = new OrderItem.Builder()
.WithId("1")
.WithQuantity(2)
.WithName("Apple")
.WithDescription("A delicious apple")
.WithAmount(Money.FromEuros(Currency.EUR, 1.50m))
.WithTax(Money.FromEuros(Currency.EUR, 0.14m))
.WithItemCategory(ItemCategory.PHYSICAL)
.WithVatCategory(VatCategory.LOW)
.Build();
OrderItem pears = new OrderItem.Builder()
.WithId("2")
.WithQuantity(3)
.WithName("Pear")
.WithDescription("A delicious pear")
.WithAmount(Money.FromEuros(Currency.EUR, 1.75m))
.WithTax(Money.FromEuros(Currency.EUR, 0.16m))
.WithItemCategory(ItemCategory.PHYSICAL)
.WithVatCategory(VatCategory.LOW)
.Build();
Discount
A discount in the order is also provided by an order item but the amount and (if applicable) the tax fields have a negative value. The following examples describe a discount of 10 euros:
PHP
$discount = OrderItem::createFrom([
'id' => '1',
'name' => 'Discount',
'description' => 'Frequent buyer',
'quantity' => 1,
'amount' => Money::fromDecimal('EUR', -10),
'tax' => Money::fromDecimal('EUR', -0.9),
'category' => ProductType::PHYSICAL,
'vatCategory' => VatCategory::LOW
]);
Java
OrderItem discount = new OrderItem.Builder()
.withId("1")
.withQuantity(1)
.withName("Discount")
.withDescription("Frequent buyer")
.withAmount(Money.fromEuros(Currency.EUR, new BigDecimal("-10")))
.withTax(Money.fromEuros(Currency.EUR, new BigDecimal("-0.9")))
.withItemCategory(ItemCategory.PHYSICAL)
.withVatCategory(VatCategory.LOW)
.build();
.NET
OrderItem discount = new OrderItem.Builder()
.WithId("1")
.WithQuantity(1)
.WithName("Discount")
.WithDescription("Frequent buyer")
.WithAmount(Money.FromEuros(Currency.EUR, -10m))
.WithTax(Money.FromEuros(Currency.EUR, -0.9m))
.WithItemCategory(ItemCategory.PHYSICAL)
.WithVatCategory(VatCategory.LOW)
.Build();
The Amount
of the MerchantOrder
must match the sum of the order items if the OrderItems
is supplied.
The total amount can be calculated as follows:
PHP
$orderTotalInCents = 0;
foreach ($orderItems as $orderItem) {
$priceTaxInclusiveInCents = $orderItem->getAmount()->getAmount();
$orderTotalInCents += $priceTaxInclusiveInCents * $orderItem->getQuantity();
}
$orderAmount = Money::fromCents('EUR', $orderTotalInCents);
Java
BigDecimal orderTotal = BigDecimal.ZERO;
for (OrderItem orderItem : orderItems) {
BigDecimal amount = orderItem.getAmount().getAmount();
BigDecimal quantity = new BigDecimal(orderItem.getQuantity());
orderTotal = orderTotal.add(amount.multiply(quantity));
}
Money orderAmount = Money::fromEuros(Currency.EUR, orderTotal);
.NET
decimal totalAmount = 0.0m;
foreach (var orderItem in orderItems)
{
decimal amount = orderItem.Amount.Amount;
int quantity = orderItem.Quantity;
totalAmount += quantity * amount;
}
Money orderAmount = Money.FromEuros(Currency.EUR, totalAmount);
Should there be an incorrect order which was sent and Rabo OmniKassa can repair it, then an attempt is made to correct the order by removing or shortening any data. This applies only in extreme cases and may result in specific payment methods not being available for this order.
Required fields per payment method
Regardless of the payment method, at least the merchantOrderId
, amount
and the merchantReturnUrl
must be included in each order.
Depending on the payment method, additional information must be included in the order.
The table below shows what data this is, broken down by payment method:
Payment method | Additional information in the order |
---|---|
iDEAL | No additional information is required for this payment method. |
PayPal | Although not mandatory, we also recommend that you include order items in the order for additional security regarding PayPal's payment to the webshop owner. |
Bancontact | Although not mandatory, we advise you to include the delivery address (or, if not known, the billing address) in the order for additional certainty about a successful payment. |
Visa | Although not mandatory, we advise you to include the delivery address (or, if not known, the billing address) in the order for additional certainty about a successful payment. |
MasterCard | Although not mandatory, we advise you to include the delivery address (or, if not known, the billing address) in the order for additional certainty about a successful payment. |
V PAY | Although not mandatory, we advise you to include the delivery address (or, if not known, the billing address) in the order for additional certainty about a successful payment. |
Maestro | Although not mandatory, we advise you to include the delivery address (or, if not known, the billing address) in the order for additional certainty about a successful payment. |
Sofort | No additional information is required for this payment method. |
If for a payment method the mandatory additional information is missing in the order then the customer cannot use this method to fulfill the payment. If the payment method was included in the order using the PaymentBrand field, the announcement will be refused by Rabo OmniKassa.
Besides an order is also an instance of an Endpoint
needed. With this Endpoint
it is possible to perform all calls towards the Rabo OmniKassa.
An Endpoint
is instantiated with three parameters: an Url, A Base64 encoded signing key, and a TokenProvider
implementation.
The URL determines whether the production environment or the sandbox environment is linked:
Environment | Description |
---|---|
Production | In this environment actual payments are done that are depreciated from the customer's account and transferred to the owner of the webshop. |
Sandbox | This is a test environment. Payments in this environment are simulated and are only intended to test the connections with your webshop. |
The environments can be configured in Rabo OmniKassa Dashboard - for example, which payment methods should be offered.
The signing key is a secret key that can be found in the Rabo OmniDashboard. This signing key is BASE64 encoded.
The signing key is used by Rabo Omnikassa to cryptographically sign the data in the merchantReturnUrl
as well as the data in the messages that are sent to the webhook.
The webshop must use this information to verify the authenticity of the message. This is done automatically by the SDK..
Finally, we need the implementation of the TokenProvider
. This implementation is responsible for providing and storing token information.
For example, an implementation can store the data in a database, on a file system, or in memory.
The aim is that your TokenProvider
provides a refresh token by default -it must be available in the TokenProvider
before the first call is made.
This token can be found in the Rabo OmniKassa Dashboard and is a unique token with long term validity (typically a few years). It is used to request an access token from Rabo Omnikassa.
The access token is valid for a limited amount of time (typically one hour) and must be used in all subsequent calls. This token is delivered to the TokenProvider
for storage and also for reading.
PHP
<?php
use nl\rabobank\gict\payments_savings\omnikassa_sdk\connector\TokenProvider;
class InMemoryTokenProvider extends TokenProvider
{
private $map = array();
/**
* Construct the in memory TokenProvider with the given refresh token.
* @param string $refreshToken The refresh token used to retrieve the access tokens with.
*/
public function __construct($refreshToken)
{
$this->setValue(static::REFRESH_TOKEN, $refreshToken);
}
/**
* Retrieve the value for the given key.
*
* @param string $key
* @return string Value of the given key or null if it does not exists.
*/
protected function getValue($key)
{
return array_key_exists($key, $this->map) ? $this->map[$key] : null;
}
/**
* Store the value by the given key.
*
* @param string $key
* @param string $value
*/
protected function setValue($key, $value)
{
$this->map[$key] = $value;
}
/**
* Optional functionality to flush your systems.
* It is called after storing all the values of the access token and can be used for example to clean caches or reload changes from the database.
*/
protected function flush()
{
}
}
Java
public class InMemoryTokenProvider extends TokenProvider {
private Map<FieldName, String> map = new HashMap<>();
public InMemoryTokenProvider(String refreshToken) {
setValue(FieldName.REFRESH_TOKEN, refreshToken);
}
@Override
public String getValue(FieldName key) {
return map.get(key);
}
@Override
public void setValue(FieldName key, String value) {
map.put(key, value);
}
}
.NET
using System;
using System.Collections.Generic;
using OmniKassa;
namespace MyNamespace
{
public sealed class InMemoryTokenProvider : TokenProvider
{
private Dictionary<FieldName, String> mMap = new Dictionary<FieldName, String>();
public InMemoryTokenProvider(String refreshToken)
{
SetValue(FieldName.REFRESH_TOKEN, refreshToken);
}
protected override String GetValue(FieldName key)
{
mMap.TryGetValue(key, out string value);
return value;
}
protected override void SetValue(FieldName key, String value)
{
if (mMap.ContainsKey(key))
{
mMap[key] = value;
}
else
{
mMap.Add(key, value);
}
}
}
}
This provider can then be used to create an Endpoint as follows:
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\Environment;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\signing\SigningKey;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\endpoint\Endpoint;
$signingKey = new SigningKey(base64_decode('{signing_key}'));
$inMemoryTokenProvider = new InMemoryTokenProvider('{refresh_token}');
$endpoint = Endpoint::createInstance(Environment::PRODUCTION, $signingKey, $inMemoryTokenProvider, $userAgent, $partnerReference);
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.*;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.connector.TokenProvider;
TokenProvider inMemoryTokenProvider = new InMemoryTokenProvider("{refresh_token}");
Endpoint endpoint = Endpoint.createInstance(Environment.PRODUCTION, "{signing_key}", inMemoryTokenProvider, "{userAgent}","{partnerReference}");
.NET
using OmniKassa;
using MyNamespace;
TokenProvider inMemoryTokenProvider = new InMemoryTokenProvider("{refresh_token}");
Endpoint endpoint = Endpoint.Create(Environment.SANDBOX, "{signing_key}", inMemoryTokenProvider, "{userAgent}","{partnerReference}");
To link to the sandbox environment, the constant Environment.SANDBOX
must be used as the first parameter. Don't forget to also replace the refresh token and the signing key that are specific to the sandbox environment.
With this Endpoint
we can announce the order. As a response to the order announcement Rabo OmniKassa returns a unique ID to identify the order as well as a URL to the payment pages. The customer must be redirected to this URL in order to pay for the order.
PHP
$response = $endpoint->announce($order);
//Redirect user to Rabo OmniKassa
header('Location: ' . $response->getRedirectUrl());
Java
MerchantOrderResponse response = endpoint.announce(order);
// Redirect user to Rabo OmniKassa
return "redirect:" + response.getRedirectUrl();
.NET Standard
using Microsoft.AspNetCore.Mvc;
MerchantOrderResponse merchantOrderResponse = await endpoint.Announce (order);
String redirectUrl = response.RedirectUrl;
return new RedirectResult(redirectUrl);
.NET
using System.Web.Mvc;
MerchantOrderResponse merchantOrderResponse = endpoint.Announce (order);
String redirectUrl = response.RedirectUrl;
return new RedirectResult(redirectUrl);
The object of type MerchantOrderResponse
as returned by the Java SDK contains the following fields:
Field | Description |
---|---|
redirectUrl | The URL to which the customer must be redirected to in order to pay for the order. |
omnikassaOrderId | A unique ID that Rabo OmniKassa will assign to the order. This ID is needed to link the payment result as returned by the webhook notification mechanism to the correct order (see Receive updates about orders). |
The default behavior for an online payment is to redirect the customer to the payment pages of Rabo OmniKassa after the order has been announced. These are Rabobank-branded pages hosted by Rabo OmniKassa and they guide the customer through the payment process by presenting a list of payment brands and to ask the customer for additional details, depending on the selected payment brand. For an improved online payment experience Rabo OmniKassa provides means to skip some of these steps by letting the webshop supply payment brand information. For example, in the checkout process the webshop can already provide an option for the customer to select iDEAL as a payment brand as well as the bank. In this section we describe how the SDK facilitates this improved experience.
The first improvement is to allow the customer to select the payment brand in the webshop. For this the SDK provides functionality to retrieve the payment brands that are currently configured and active within Rabo OmniKassa for the web shop. For a technical description on how to obtain the brands see Request available payment brands. The returned payment brand information can then be used for example to populate a select box in the webshop.
Once the customer has selected a payment brand, the webshop needs to supply two additional fields in the order announcement:
- The
paymentBrand
field must contain the name of the selected payment brand, for exampleIDEAL
. - The
paymentBrandForce
field must specify whether the customer can select an alternative payment in the hosted payment pages.
We explain the payment method and the force options in more detail. When the payment method is IDEAL
and the Force
option FORCE_ONCE
has been specified, then the customer will immediately start an iDEAL payment upon arrival at
Rabo OmniKassa and thus arrives on the bank selecting screen. The customer then has the option to finalize the payment
or to choose another payment method by clicking on <Choose Other Payment method>
. With the FORCE_ALWAYS
it is not
possible for the customer to choose another payment method. The only options are to approve or cancel the payment after
selecting the bank.
The second improvement applies only to iDEAL and allows the customer to also select his or her bank in the webshop. For this the SDK provides functionality to retrieve the list of participating banks. For a technical description on how to obtain this list please consult Request available iDEAL issuers. The returned list of banks can then be used to populate another select box in the webshop that becomes visible after the customer has selected iDEAL as payment brand.
Once the bank has been selected the webshop needs to include the ID of the bank in the paymentBrandMetaData
field in
addition to the above-mentioned paymentBrand
the paymentBrandForce
fields. The paymentBrandMetaData
field is a
key-value map. To specify the bank include an entry in this map with key 'issuerId' and as value the ID of the bank as
specified in the issuer list, for example 'RABONL2U'.
By implementing these 2 improvements in the webshop the customer will be immediately redirected to the iDEAL page of the selected bank after announcing the order to authorize the transaction.
A final optimization can be achieved by setting the skipHppResultPage
field in the order announcement to true
. After
authorizing the transaction in the iDEAL page of the selected bank, the customer will be immediately redirected back to
the webshop. The success page (also referred to as the “Thank You” page) of the hosted payment pages will be skipped in
this case.
In this section we specify how to include the name of the customer in the order information such that it will be visible in the Omni Dashboard. There are two ways on how to achieve this.
- The first and preferred approach is to specify the field
fullName
of theCustomerInformation
structure. - If this field is not set then OmniKassa will use the name as specified in the shipping details (if included) or billing details (if included), where the shipping details will take precedence.
When redirected to the payment pages of Rabo Omnikassa the customer can pay the order. When this is done, the customer is automatically redirected back to the webshop via the merchantReturnUrl
specified in the order announcement.
With this URL
some query parameters will be included that relate to the order, namely:
Parameter | Description |
---|---|
order_id |
This is the order ID as specified in the order announcement. |
status |
The current known status of the order. |
signature |
The signature makes it possible to verify that the request is authentic. |
To verify that the signature is authentic, the following code can be used.
It is also advisable to make use of the PaymentCompletedResponse
class so that the order_id
, status
and signature
will be cleaned if they contain invalid/unsafe values.
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\signing\SigningKey;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\response\PaymentCompletedResponse;
$orderId = $_GET['order_id'];
$status = $_GET['status'];
$signature = $_GET['signature'];
$signingKey = new SigningKey(base64_decode('{signing_key}'));
$paymentCompletedResponse = PaymentCompletedResponse::createInstance($orderId, $status, $signature, $signingKey);
if (!$paymentCompletedResponse) {
throw new Exception('The payment completed response was invalid.');
}
// Use these variables instead of using the URL parameters ($orderId and $status). Input validation has been performed on these values.
$validatedMerchantOrderId = $paymentCompletedResponse->getOrderID();
$validatedStatus = $paymentCompletedResponse->getStatus();
// ... complete payment
Java
void paymentCompleted(HttpServletRequest request) {
byte[] signingKey = Base64Utils.decodeFromString("{signing_key}");
String orderId = request.getParameter("order_id");
String status = request.getParameter("status");
String signature = request.getParameter("signature");
PaymentCompletedResponse paymentCompletedResponse;
try {
paymentCompletedResponse = PaymentCompletedResponse.newPaymentCompletedResponse(orderId, status, signature, signingKey);
} catch (RabobankSdkException invalidSignatureException){
throw new IllegalStateException("The payment completed response was invalid.", invalidSignatureException);
}
// Use these variables instead of using the URL parameters (orderId and status). Input validation has been performed on these values.
String validatedOrderId = paymentCompletedResponse.getOrderID();
String validatedStatus = paymentCompletedResponse.getStatus();
//... complete payment
}
.NET
using OmniKassa.Model.Response;
using OmniKassa.Model.Enums;
PaymentCompletedResponse response = PaymentCompletedResponse.Create(Request.QueryString, "{signing_key}");
String validatedOrderId = paymentCompletedResponse.OrderId;
PaymentStatus validatedStatus = paymentCompletedResponse.Status;
If the answer is invalid, it is advisable to redirect the customer to an error page but to consider the order as open
.
At a later stage, the actual status of the order can be requested by means of notifications.
All the status transitions of an order are tracked by the Rabo OmniKassa so that they can be offered to the webshop with the help of notifications.
The Rabo OmniKassa does this by sending a notification to the webhookUrl
through a Post
request with the notification as JSON.
The webhookUrl
can be configured in the dashboard of Rabo OmniKassa.
A notification looks like this:
Notification
{
"authentication": "eyJraWQiOiJHS0wiLCJhbGciOiJFUzI1NiJ9.eyJwayMiOjUwMiwiY2lkIjoiYzhjYy1mMThjIiwiZXhwIjoxNDc5MTIyODc2fQ.MEUCIQC2Z5WUVTAKcBHISsOVMJIJE8PAbVe5x1ior4bgrTcgCwIgLNoVIWEmSbQekJTccM89sosAY-8JzN47DGjvdPGdF0w",
"expiry": "2016-11-25T09:53:46.765+01:00",
"eventName": "merchant.order.status.changed",
"poiId": "123"
}
With this JSON it is possible to build up an AnnouncementResponse
with which the actual information of the orders can be retrieved.
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\endpoint\Endpoint;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\Environment;
$signingKey = new SigningKey(base64_decode('{signing_key}'));
$inMemoryTokenProvider = new InMemoryTokenProvider('{refresh_token}');
$endpoint = Endpoint::createInstance(Environment::PRODUCTION, $signingKey, $inMemoryTokenProvider);
$json = file_get_contents('php://input');
$announcementResponse = new AnnouncementResponse($json, $signingKey);
do {
$response = $endpoint->retrieveAnnouncement($announcementResponse);
$results = $response->getOrderResults();
foreach($results as $result) {
//... Update the order status using the properties in $result
}
} while ($response->isMoreOrderResultsAvailable());
Java
@RequestMapping(value = "/webhook", method = RequestMethod.POST)
ResponseEntity webhook(@RequestBody ApiNotification apiNotification) throws RabobankSdkException {
byte[] signingKey = Base64Utils.decodeFromString("{signing_key}");
apiNotification.validateSignature(signingKey);
Endpoint endpoint = Endpoint.createInstance(...);
MerchantOrderStatusResponse merchantOrderStatusResponse;
do {
merchantOrderStatusResponse = endpoint.retrieveAnnouncement(apiNotification);
for (MerchantOrderResult result : merchantOrderStatusResponse:getOrderResults()) {
// Update the order status using the properties in result
}
} while (merchantOrderStatusResponse.moreOrderResultsAvailable());
return new ResponseEntity(HttpStatus.OK);
}
.NET
using System.Web.Mvc;
using OmniKassa.Model.Response;
using OmniKassa.Model.Response.Notification;
[HttpPost]
public ActionResult Webhook(ApiNotification notification)
{
MerchantOrderStatusResponse response;
do
{
response = omniKassa.RetrieveAnnouncement(notification);
foreach(MerchantOrderResult result in response.OrderResults)
{
// Update the order status using the properties in result
}
}
while (response.MoreOrderResultsAvailable);
return new HttpStatusCodeResult(HttpStatusCode.OK);
}
This step also verifies the signature of the notification. If the validation fails, for example when a different signing key is active in the dashboard, then the order data will not be retrieved. Rabo Omnikassa will send a new notification at a later time. More information regarding this process can be found in the User Manual of Rabo OmniKassa.
The MerchantOrderStatusResponse
object returned by the call to the retrieveAnnouncement
method consists of the following properties:
Field | Description |
---|---|
orderResults |
This is an array consisting of 0 or more objects of type MerchantOrderResult. The result of an order is included in each object. The composition of this item is further explained in further detail in this section. |
moreOrderResultsAvailable |
When calling retrieveAnnouncement , the data of up to 100 objects is returned in OrderResults, to keep the volume of the response manageable. If more than 100 orders have been processed, the MoreOrderResultsAvailable field has a value of true and a new call to RetrieveAnnouncement can query the results of the next set of up to 100 orders. This process can be repeated as long as moreOrderResultsAvailable has a value of false. |
As shown above, an object of type MerchantOrderResult
contains the data of a single order. The following table explains the fields of this item.
Field | Description |
---|---|
merchantOrderId |
The ID of the order as specified by the webshop when the order was announced. |
omniKassaOrderId |
The unique ID assigned by OmniKassa to the order at the time of the announcement. |
poiId |
The unique ID that identifies the webshop. |
orderStatus |
The status of the order. The following values are possible: |
COMPLETED: The full amount of the order is paid by the customer. | |
CANCELLED: The order was canceled by the customer. | |
EXPIRED: The order has expired without the customer having paid. | |
orderStatusDateTime |
The most recent timestamp of the order. |
If there was no payment attempt, this field will contain the time the order was announced at OmniKassa. | |
Otherwise, this field contains the time of the most recent payment attempt. | |
errorCode |
This field is reserved for future use. Currently, this field does not contain a value. |
paidAmount |
The amount paid by the customer. In case of COMPLETED, it is equal to the order amount as given by the webshop at the announcement. When CANCELLED and EXPIRED, this field will have a value of 0. |
totalAmount |
The original order amount as specified by the webshop when announcing the order. |
transactions |
A list of transactions with type AUTHORIZE and PAYMENT of type Transaction. The composition of this item is further explained in further detail in this section. (Since version 1.18) |
As shown above, an object of type Transaction
contains the data of a single transaction. The following table explains the fields of this item.
Field | Description |
---|---|
id |
The unique ID assigned by OmniKassa to the transaction at the time it was created. Needed for refunds |
paymentBrand |
The paymentbrand of this transaction. Can be one of the following: IDEAL, PAYPAL, MASTERCARD, VISA, BANCONTACT, MAESTRO, V_PAY, SOFORT. |
type |
The type of transaction, can be AUTHORIZE or PAYMENT |
status |
The status of the transaction. The following values are possible: |
SUCCESS: The transaction was successful. | |
ACCEPTED : The transaction was accepted by the paymentprovider | |
CANCELLED: The transaction was canceled by the customer. | |
EXPIRED: The transaction has expired without the customer having paid. | |
FAILURE: The transaction has failed. | |
amount |
The amount the consumer was charged in this transaction. |
confirmedAmount |
The amount the consumer paid in this transaction. |
startTime |
The timestamp of when this transaction was started |
lastUpdateTime |
The most recent timestamp of the last update of the transaction. |
The SDK also provides functionality to look up all payment brands of a webshop as configured in the dashboard of Rabo OmniKassa.
This information can be used to determine which payment brands are available to the customer.
It is typically used in conjunction with the paymentBrand
and paymentBrandForce
fields of an order announcement (Order announcement).
Important: The payment brands should not be requested real-time for each payment, but instead be cached locally and updated at certain time intervals (e.g. every few hours).
Given an Endpoint
(Creating endpoint) we can look up the payment brands as followings.
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\PaymentBrandsResponse;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\PaymentBrandInfo;
$response = $endpoint->retrievePaymentBrands();
$paymentBrands = $response->getPaymentBrands();
foreach($paymentBrands as $paymentBrand) {
$name = $paymentBrand->getName();
$active = $paymentBrand->isActive();
// use the name and the active variables for further processing
}
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.PaymentBrandsResponse;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.PaymentBrandInfo;
PaymentBrandsResponse response = endpoint.retrievePaymentBrands();
for (PaymentBrandInfo paymentBrand : response.getPaymentBrands()) {
String name = paymentBrand.getName();
PaymentBrandStatus status = paymentBrand.getStatus();
// use the name and status variables for further processing
}
.NET
using OmniKassa.Model.Response;
PaymentBrandsResponse response = endpoint.RetrievePaymentBrands();
foreach(PaymentBrandInfo brand in response.PaymentBrands)
{
String name = brand.Name;
Boolean active = brand.IsActive;
// use the name and active variables for further processing
}
As shown above the retrievePaymentBrands()
method of the Endpoint class returns an instance of PaymentBrandsResponse
.
This class provides a method getPaymentBrands()
that returns a list containing all payment brands that are configured for the webshop.
Each element of this list is an object of type PaymentBrandInfo
containing the details of a single payment brand, as shown in the following table.
Field | Description |
---|---|
name |
A string containing the name of the payment brand. This string may contain one of the following values: |
IDEAL | |
PAYPAL | |
MASTERCARD | |
VISA | |
BANCONTACT | |
MAESTRO | |
V_PAY | |
SOFORT | |
Note: Keep in mind that other values can be expected as well whenever Rabo OmniKassa is extended with new payment brands. | |
active |
A boolean indicating if the payment brand is active (true) or inactive (false). |
Only the payment brands that are returned in this list and are active can be used for payments.
In this section we explain how to obtain the iDEAL issuers. This functionality is typically used to directly start an iDEAL transaction from the webshop without first redirecting the customer to the payment pages of Rabo OmniKassa to select iDEAL as the payment brand and then the issuer.
Important: The list of iDEAL issuers should not be requested real-time for each payment, but instead be cached locally and updated daily.
Given an Endpoint
(Creating endpoint) we can obtain this list as follows.
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\response\IdealIssuersResponse;
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\response\IdealIssuersInfo;
$response = $endpoint->retrieveIDEALIssuers();
$issuers = $response->getIssuers();
foreach($issuer as $issuers) {
// use the properties in the issuer variable for further processing
}
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.IdealIssuersResponse;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.IdealIssuer;
IdealIssuersResponse response = endpoint.retrieveIdealIssuers();
for (IdealIssuer issuer : response.getIssuers()) {
// use the properties in the issuer variable for further processing
}
.NET
using OmniKassa.Model.Response;
IdealIssuersResponse response = endpoint.RetrieveIdealIssuers();
foreach(IdealIssuer issuer in response.IdealIssuers)
{
// use the properties in the issuer variable for further processing
}
As shown above the retrieveIdealIssers()
method of the Endpoint class returns an instance of IdealIssuersResponse
.
This class provides a method getIssuers()
that returns a list of all available iDEAL issuers.
Each element of this list is an object containing the details of a single iDEAL issuer as shown in the following table.
Field | Description |
---|---|
id |
A string of at most 11 characters containing the unique ID of the iDEAL issuer. This ID must be used in the paymentBrandMetaData field of an order to immediately start an iDEAL transaction for this issuer. |
name |
The name of the Issuer as should be presented to the customer when rendering the list of iDEAL issuers. This field is a string of at most 35 characters. |
logos |
A list of objects containing logo details of the issuer. This information can be used to render the logo of the issuer in the webshop. See table below for more details on the logo properties. |
countryNames |
Contains the country names in the official languages of the country, separated by a '/' symbol. As prescribed by the iDEAL integration guide this only needs to be displayed if there are banks from more than one country on the Issuer list (which is currently not the case). |
The table below contains the properties of an iDEAL issuer logo.
Field | Description |
---|---|
url |
A publicly accessible URL where you can download the logo of the issuer. |
mimeType |
The mime type (also referred to as the media type) of the logo. This always an image type. |
After a transaction is successful, it is possible to initiate a refund. The refund API exposes the same functionality for refunds as the Rabo Smart Pay dashboard. For more functional documentation about refunds see the Rabo Smart Pay manual.
The Refund API contains three endpoints for:
- Initiating a refund
- Retrieving details such as the status of a refund.
- Retrieving the refundable amount of a transaction. Additionally, the webhook mechanism now also exposes the transactions belonging to an order. A transaction ID from the transaction is needed to initiate or request the status of a refund.
In this section we explain how to initiate a refund request.
Given an Endpoint
(Creating endpoint), a transactionId, an amount, a description and optionally a vatCategory we can initiate a refund as follows
PHP
use nl\rabobank\gict\payments_savings\omnikassa_sdk\model\request\InitiateRefundRequest;
$merchantRequestReference = '{unique UUID}';
$request = new InitiateRefundRequest(Money::fromCents('EUR', $amount), $description,$vatCategory);
$response = $endpoint->initiateRefundTransaction($request, $transactionId, $merchantRequestReference);
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.Money;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.request.InitiateRefundRequest;
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.RefundDetailsResponse;
Money money = Money.fromEuros(EUR, BigDecimal.valueOf(Double.parseDouble(amount));
InitiateRefundRequest refundRequest = new InitiateRefundRequest(money, description,StringUtils.isEmpty(vatCategory) ? null : VatCategory.valueOf(vatCategory));
RefundDetailsResponse response = endpoint.initiateRefundTransaction(refundRequest, UUID.fromString(transactionId), UUID.randomUUID());
.NET
using OmniKassa.Model.Response;
using OmniKassa.Model.Request;
var refundRequest = new InitiateRefundRequest(amount, description, vatCategory);
webShopModel.RefundDetailsResponse = endpoint.InitiateRefundTransaction(refundRequest, transactionId, Guid.NewGuid());
In this section we explain how retrieve the details of a refund
Given an Endpoint
(Creating endpoint), a transactionId and a refundId we can obtain the details of a refund as follows.
PHP
$response = $endpoint->fetchRefundTransaction($transactionId, $refundId);
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.RefundDetailsResponse;
RefundDetailsResponse refundDetailsResponse = endpoint.fetchRefundTransaction(UUID.fromString(transactionId), UUID.fromString(refundId));
.NET
using OmniKassa.Model.Response;
var transactionId = Guid.Parse(transactionIdStr);
var refundId = Guid.Parse(refundIdStr);
var RefundDetailsResponse = endpoint.FetchRefundTransaction(transactionId, refundId);
In this section we explain how retrieve the details of a transaction, refundableMoney and expirydate, you need to start a refund.
Given an Endpoint
(Creating endpoint) and a transactionId we can obtain the details of a transaction as follows.
PHP
$response = $endpoint->fetchRefundableTransactionDetails($transactionId);
Java
import nl.rabobank.gict.payments_savings.omnikassa_frontend.sdk.model.response.TransactionRefundableDetailsResponse;
TransactionRefundableDetailsResponse response = endpoint.fetchRefundableTransactionDetails(UUID.fromString(transactionId));
.NET
using OmniKassa.Model.Response;
using OmniKassa.Model.Request;
var transactionId = Guid.Parse(transactionIdStr);
var refundableTransactionDetailsResponse = endpoint.FetchRefundableTransactionDetails(transactionId);