Introduction
The Paymentwindow is the easiest way to get a payment through for your order.
It simply requires a form that is submitted towards onpay.io containing the details of the payment to be made, after the customer has paid they are returned to an url selected by you.
Post form
<form method="post" action="https://onpay.io/window/v3/" accept-charset="UTF-8">
<input type="hidden" name="onpay_gatewayid" value="20007895654">
<input type="hidden" name="onpay_currency" value="DKK">
<input type="hidden" name="onpay_amount" value="12000">
<input type="hidden" name="onpay_reference" value="AF-847824">
<input type="hidden" name="onpay_hmac_sha1" value="f31dc4b392c6a7a25815e3e2bc39bc0fe02cc5a7">
<input type="hidden" name="onpay_accepturl" value="https://example.com/accept">
<input type="hidden" name="onpay_website" value="https://example.com/">
<input type="submit" value="Start payment of 120.00 DKK">
</form>
The form should be rendered, and submitted in the cardholders browser, and submitted against https://onpay.io/window/v3/
Parameters
Below is a list of all parameters the window supports, any parameter not prefixed with onpay_
will be passed on to the different callbacks/redirects.
Parameter | Value | Description | Example |
---|---|---|---|
onpay_gatewayid* | [0-9]+ |
The unique gatewayid for your paymentgateway | 20007895654 |
onpay_currency* | [0-9]{3} or [A-Z]{3} |
The ISO4217 currency code, either 3 digit numeric or alpha code 1 | DKK or 208 |
onpay_amount* | [0-9]+ |
The amount for the order in minor units. Is required only when type is transaction |
12000 For 120.00 DKK. |
onpay_reference* | [a-zA-Z0-9\-\.]{1,36} |
Has to be unique, your own internal reference, even tho both upper and lower case is accepted they are treated the same in the system | AF-847824 |
onpay_hmac_sha1* | [a-f0-9]+ |
A SHA1 HMAC of all parameteres ordered alphabetically and the shared secret set in the management panel. See here for more details on calculating the hash. | a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 |
onpay_accepturl* | Valid URL | Where to send the user after a successful reservation is made. | https://example.com/accept |
onpay_website* | Valid URL | URL to the website where the checkout process was started | https://example.com/ |
onpay_type | transaction or subscription |
Defaults to transaction . subscription is only supported by the following payment methods: card , applepay and googlepay |
transaction |
onpay_method | See Methods | If none is provided, the user is presented with a choice of which method to use. | |
onpay_3dsecure | forced |
If set to forced , then all creditcard transactions are required to run with 2-factor authentication if provided by the card brand. |
|
onpay_language | da , de , en , es , fo , fr , it , nl , no , pl or sv |
The language of the payment window. Defaults to English | en |
onpay_declineurl | Valid URL | Where to send the user in case payment failed, if this value is not set the accepturl will be used! | https://example.com/decline |
onpay_callbackurl | Valid URL | If set, onpay system will make a direct call to this URL to signal that a payment suceeded. See more here | https://example.com/callback |
onpay_design | [a-zA-Z0-9 ]+ |
The name of the window design to use. Use if you have more than one design defined in the backend | window1 |
onpay_expiration | [0-9]+ |
Seconds that the payment will be available before expiring. Default is 1 day (86400 seconds). | 4200 |
onpay_testmode | [01] |
If set to 1 the window will run in testmode, provided that it has been enabled. It is only necessary to set this parameter if production mode is also enabled | 1 |
onpay_info_* | Additional info about the customer, see Info parameters | ||
onpay_subscription_with_transaction | [01] |
Set along with onpay_type=subscription and a valid value in onpay_amount (Which is then required). When set to 1, a transaction will be created from the subscription on completion, with the amount defined in onpay_amount . The value of onpay_amount must be more than 100 . |
1 |
onpay_cart_* | Cart information, required on certain payment methods, see Cart parameters |
Methods
The following methods are supported. When a specific method is sent to the payment window, the cardholder will be redirected to said method. If none is provided, the user is presented with a choice of which method to use.
Method | Parameter | Description | Supports subscriptions |
---|---|---|---|
Anyday | anyday |
Payment using Anyday. Only currency DKK allowed. |
No |
Apple Pay | applepay |
Payment using Apple Pay. Browser support required | Yes |
Credit card | card |
Payment using credit cards. | Yes |
Google Pay | googlepay |
Payment using Google Pay. Browser support required | Yes |
MobilePay Online | mobilepay |
Payment using MobilePay Online. Currencies allowed: DKK NOK SEK GBP USD EUR . |
No |
Swish | swish |
Payment through Swish. Only currency SEK allowed. |
No |
ViaBill | viabill |
Payment using ViaBill. Currencies allowed: DKK EUR |
No |
Vipps | vipps |
Payment through Vipps. Only currency NOK allowed. |
No |
Info parameters
Besides the payment specific parameters, it is mandated by the card-schemes that further details should be provided if they are available. This is used to conduct 3DSv2, the updated standard for cardholder authentication according to the rule set forth in PSD2.
The data is utilized by the card issuer to make a risk assessment on the transaction, and determine whether to do what is called a "frictionless flow". A frictionless flow, means that the cardholder will not be prompted to enter any data but the transaction will still be marked as validated with 3D-Secure.
Parameter | Value | Description | Example |
---|---|---|---|
onpay_info_account_id | \w{1,64} |
Account identifier, could be a customer number. | ABC-455454 |
onpay_info_account_date_created | date | When the account was created at the merchant. | 2020-02-15 |
onpay_info_account_date_change | date | When the account was last changed, this includes billing and shipping address. | 2020-03-02 |
onpay_info_account_date_password_change | date | When the account last had its password changed. | 2020-03-02 |
onpay_info_account_purchases | [0-9]+ |
The number of completed purchases with this account in the last 6 months (excluding the current one). | 3 |
onpay_info_account_attempts | [0-9]+ |
The number of payment attempts on this account in the past 24 hours. | 0 |
onpay_info_account_shipping_first_use_date | date | The date of when the shipping address was first used on this account. | 2020-02-15 |
onpay_info_account_shipping_identical_name | Y , N |
Indicates whether the account holder name matches the shipping details. | Y |
onpay_info_account_suspicious | Y , N |
Indicates whether the merchant has experienced suspicious actitivy on the account previously (including fraud) | N |
onpay_info_account_attempts_day | [0-9]+ |
Number of transactions attempted (successful or not) for this account, in the past 24 hours. | 3 |
onpay_info_account_attempts_year | [0-9]+ |
Number of transactions attempted (successful or not) for this account, in the past 365 days. | 3 |
onpay_info_address_identical_shipping | Y , N |
Indicates whether the billing and shipping address are the same, only relevant if actually shipping anything. | Y |
onpay_info_billing_address_city | .{1,50} |
Billing address city | Skanderborg |
onpay_info_billing_address_country | [0-9]{3} |
Billing address country code, in the numeric format from ISO-3166-1 | 208 |
onpay_info_billing_address_line1 | .{1,50} |
First line of the address | Højvangen 4 |
onpay_info_billing_address_line2 | .{1,50} |
Second line of the address, if needed. | |
onpay_info_billing_address_line3 | .{1,50} |
Third line of the address, if needed. | |
onpay_info_billing_address_postal_code | \w{1,16} |
The postal code of the address. | 8660 |
onpay_info_billing_address_state | \w{1,3} |
The subdivision code of the address, according to ISO-3166-2 (Only the part after the country code, so US-NY becomes NY . Should only be used when relevant for the country. |
NY |
onpay_info_shipping_address_city | .{1,50} |
Shipping address city | Skanderborg |
onpay_info_shipping_address_country | [0-9]{3} |
Shipping address country code, in the numeric format from ISO-3166-1 | 208 |
onpay_info_shipping_address_line1 | .{1,50} |
First line of the address | Højvangen 4 |
onpay_info_shipping_address_line2 | .{1,50} |
Second line of the address, if needed. | |
onpay_info_shipping_address_line3 | .{1,50} |
Third line of the address, if needed. | |
onpay_info_shipping_address_postal_code | .{1,16} |
The postal code of the address. | 8660 |
onpay_info_shipping_address_state | .{1,3} |
The subdivision code of the address, according to ISO-3166-2 (Only the part after the country code, so US-NY becomes NY . Should only be used when relevant for the country. |
NY |
onpay_info_name | .{2,45} |
The name of the cardholder/customer | Emil Pedersen |
onpay_info_email | .{1,254} |
The email address of the customer | emil@example.org |
onpay_info_phone_home_cc | [0-9]{1,3} |
The country code part of the phone number | 45 |
onpay_info_phone_home_number | [0-9]{1,15} |
The actual phone number, without the country part. | 37123456 |
onpay_info_phone_mobile_cc | [0-9]{1,3} |
The country code part of the phone number | 45 |
onpay_info_phone_mobile_number | [0-9]{1,15} |
The actual phone number, without the country part. | 37123456 |
onpay_info_phone_work_cc | [0-9]{1,3} |
The country code part of the phone number | 45 |
onpay_info_phone_work_number | [0-9]{1,15} |
The actual phone number, without the country part. | 37123456 |
onpay_info_delivery_email | .{1,254} |
Only used for electronic delivery. | emil@example.org |
onpay_info_delivery_time_frame | 01 , 02 , 03 , 04 |
Indicates the delivery timeframe. 01 = Electronic, 02 = Same-day shipping, 03 = Overnight shipping, 04 = Two-day or more shipping | 03 |
onpay_info_gift_card_amount | [0-9]+ |
The total amount of all gift cards within the order, only major units. (DKK 123.45 is 123) | 123 |
onpay_info_gift_card_count | [0-9]+ |
The total quantity of gift cards within the order. | 1 |
onpay_info_preorder | Y , N |
Indicates if this order is a pre-order. A pre-order is an order for an item that has not yet been released to the market. | N |
onpay_info_preorder_date | date | For a pre-ordered purchase, the expected date that merchandise will be available | 2020-04-01 |
onpay_info_reorder | Y , N |
Indicates if this order is a re-order of a previous one | N |
onpay_info_shipping_method | 01 , 02 , 03 , 04 , 05 , 06 , 07 |
The shipping method for the transaction, use the one that best describes the order. Physical goods takes precedence over digital, and then the most expensive if multiple shipping methods for same order. 01 = Ship to billing address, 02 = Ship to another verified address, 03 = Ship to other, 04 = "Ship to store" store address should be set in shipping address fields, 05 = Digital goods, 06 = Travel & event tickets, 07 = Other (digital services, electronic subscriptions, etc.) | 01 |
Cart parameters
<input type="text" name="onpay_cart_shipping_price" value="100">
<input type="text" name="onpay_cart_shipping_tax" value="20">
<input type="text" name="onpay_cart_shipping_discount" value="20">
<input type="text" name="onpay_cart_handling_price" value="500">
<input type="text" name="onpay_cart_handling_tax" value="100">
<input type="text" name="onpay_cart_discount" value="50">
<input type="text" name="onpay_cart_items[0][name]" value="Item1 name">
<input type="text" name="onpay_cart_items[0][description]" value="Long description">
<input type="text" name="onpay_cart_items[0][sku]" value="SKU">
<input type="text" name="onpay_cart_items[0][price]" value="500">
<input type="text" name="onpay_cart_items[0][tax]" value="100">
<input type="text" name="onpay_cart_items[0][quantity]" value="5">
<input type="text" name="onpay_cart_items[1][name]" value="Item2 name">
<input type="text" name="onpay_cart_items[1][price]" value="500">
<input type="text" name="onpay_cart_items[1][tax]" value="100">
<input type="text" name="onpay_cart_items[1][quantity]" value="1">
Cart information can be provided, and on some methods it is mandated.
Recommendation is to always send the data when available, to ensure future demands from payment methods can be easily met.
Parameter | Value | Description | Example |
---|---|---|---|
onpay_cart_shipping_price | [0-9]+ |
The shipping price in minor units, including any taxes but before discount. | 500 |
onpay_cart_shipping_tax | [0-9]+ |
The tax on the shipping in minor units. | 500 |
onpay_cart_shipping_discount | [0-9]+ |
Any discount that should be subtracted from the shipping_price in minor units. | 500 |
onpay_cart_handling_price | [0-9]+ |
Handling price in minor units, includes all handling related fees | 500 |
onpay_cart_handling_tax | [0-9]+ |
The tax on the handling. | 500 |
onpay_cart_discount | [0-9]+ |
The discount for the order, in minor units. Will be subtracted from the total before matching with onpay_amount |
0 or 5000 |
onpay_cart_items[0] | array of objects | An array of the different items in the cart, the number in the square bracket should be updated for each item. See example to the right. If more than 20 items, merge the 20th item together with the excess items, so there is never send more than 20 items. | |
onpay_cart_items[0][name]* | .{1,127} |
Item name | Item 1 |
onpay_cart_items[0][price]* | [0-9]+ |
The per item price in minor units, including taxes. | 100 |
onpay_cart_items[0][tax]* | [0-9]+ |
The per item tax in minor units. | 20 |
onpay_cart_items[0][quantity]* | [0-9]+ |
The quantity of items | 1 |
onpay_cart_items[0][description] | .{1,127} |
Item description | Longer description |
onpay_cart_items[0][sku] | .{1,127} |
SKU of the item | AB47871 |
Callbacks/Redirects
All called url's will contain these parameters as URL query parameters, any system set to receive these URL's should gracefully handle additional parameters prefixed with onpay_
.
Name | Type | Description | Present |
---|---|---|---|
onpay_uuid | string | Unique identifier for the transaction/subscription | Always |
onpay_number | number | The transaction or subscription number | Always |
onpay_reference | string | The provided internal reference | Always |
onpay_amount | number | The amount for the transaction, in minor units | Transactions only |
onpay_currency | string | The ISO4217 numeric currency code | Always |
onpay_hmac_sha1 | string | A SHA1 HMAC, see here for more details on calculating the hash. Present on accepturl & callbackurl, never on decline. | Conditional |
onpay_method | string | The payment method used to complete the payment | Always |
onpay_errorcode | string | If payment succeeded the errorcode will be "0", in all other cases will contain an error code | Always |
onpay_3dsecure | number | Will be set to 1, if the payment was done with 3DSecure | Conditional |
onpay_testmode | number | Will be set to 1, if the payment was done in test mode | Conditional |
onpay_cardmask | string | Will contain the cardmask if a card payment was done, example 445566XXXXXX1234 | Conditional |
onpay_cardtype | string | Will contain the type of card used, if a card payment was done | Conditional |
onpay_cardcountry | number | Will contain the country code of the card ISO-3166-1, if a card payment was done. | Conditional |
onpay_acquirercode | string | On declines this parameter will contain the acquirer specific error code. | Conditional |
onpay_uuid_transaction | string | Unique identifier for transaction created from subscription | Conditional |
onpay_number_transaction | number | Number for transaction created from subscription | Conditional |
Accept url
Upon successful completion of the payment authorization, the cardholder will be redirected to this URL.
We recommend always checking the onpay_hmac_sha1
value, to avoid any tampering.
Decline url
If the cardholder fails to complete the payment authorization, they will be redirected to this URL.
Callback url
The system will do an out of band asynchronous call to this url, containing the same parameters as the accept url.
Be aware that callbacks are executed from a simple HTTP client, which is unable to render javascript or load any images.
Only HTTP and HTTPS url's are accepted (on standard ports 80 & 443), if using HTTPS which is highly recommended a valid certificate chain has to be present.
If delivering the callback URL fails, OnPay will retry sending the callback at the following intervals:
- 10 minutes later
- 1 hour later
- 6 hours later
- 12 hours later
- 24 hours later
If the callback is not delivered successfully after 24 hours no more attempts will be made to deliver the callback.
SHA1 HMAC calculation
<?php
$secret = 'e88ebc73104651e3c8ee9af666c19b0626c9ecacd7f8f857e3633e355776baad92e67b7faf9b87744f8c6ce4303978ed65b4165f29534118c882c0fd95f52d0c';
function calculateSecret(array $params, $secret) {
// Step 1, grab the onpay_* params and order them alphabetically
$toHashArray = [];
foreach ($params as $key => $value) {
if (0 === strpos($key, 'onpay_') && 'onpay_hmac_sha1' !== $key) {
$toHashArray[$key] = $value;
}
}
ksort($toHashArray);
// Step 2, convert to a query string, and lower case
$queryString = strtolower(http_build_query($toHashArray));
// Output: onpay_accepturl=https%3a%2f%2fexample.com%2faccept&onpay_amount=12000&onpay_currency=dkk&onpay_gatewayid=20007895654&onpay_reference=af-847824
// Step 3 calculate the SHA1 HMAC
$hmac = hash_hmac('sha1', $queryString, $secret);
return $hmac;
}
$formParams = [
'onpay_gatewayid' => '20007895654',
'onpay_currency' => 'DKK',
'onpay_amount' => '12000',
'onpay_reference' => 'AF-847824',
'onpay_accepturl' => 'https://example.com/accept',
'unrelated_param' => 'bla bla bla',
];
echo calculateSecret($formParams, $secret);
// Output: 16586ad0b3446b58df92446296cf821500ac57d8
var secret = "e88ebc73104651e3c8ee9af666c19b0626c9ecacd7f8f857e3633e355776baad92e67b7faf9b87744f8c6ce4303978ed65b4165f29534118c882c0fd95f52d0c";
var formParams = new Dictionary<string, string>
{
{"onpay_gatewayid", "20007895654"},
{"onpay_currency", "DKK"},
{"onpay_amount", "12000"},
{"onpay_reference", "AF-847824"},
{"onpay_accepturl", "https://example.com/accept"},
{"unrelated_param", "bla bla bla"}
};
// Step 1, grab the onpay_* params and order them alphabetically
var onpayParams = formParams
.Where(x => x.Key.StartsWith("onpay_"))
.Where(x => x.Key != "onpay_hmac_sha1")
.OrderBy(x => x.Key)
.ToArray();
// Step 2, convert to a query string, and lowercase the result
var queryString = string.Join("&", onpayParams.Select(x => HttpUtility.UrlEncode(x.Key) + "=" + HttpUtility.UrlEncode(x.Value))).ToLower();
// Output: onpay_accepturl=https%3a%2f%2fexample.com%2faccept&onpay_amount=12000&onpay_currency=dkk&onpay_gatewayid=20007895654&onpay_reference=af-847824
// Step 3 calculate the SHA1 HMAC
var hashString = "";
using (var sha1 = new HMACSHA1(Encoding.UTF8.GetBytes(secret)))
{
var hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(queryString));
hashString = string.Join("", hash.Select(x => x.ToString("x2")));
// Output: 16586ad0b3446b58df92446296cf821500ac57d8
}
The SHA1 is calculated as an HMAC hash, over all onpay_* parameters.
- Order the onpay_* parameters alphabetically (excluding the onpay_hmac_sha1)
- Convert the list of parameters to a query string, and lower case the result
- Calculate SHA1 HMAC against the query string 2