Quickpay Form
The Quickpay Form invokes our hosted payment window simply by submitting an HTML form.
The Payment Window is in reality just an API-client hosted in a PCI Level 1 certified environment.
Please see acquirer details for acquirer specific requirements.
Simple example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!--
TIP: Append "/framed" to the action URL if you want to show the payment window in an iframe:
<form method="POST" action="https://payment.quickpay.net/framed">
And be sure to include: `allow-same-origin` , `allow-scripts` and `allow-forms` headers.
-->
<form method="POST" action="https://payment.quickpay.net">
<input type="hidden" name="version" value="v10">
<input type="hidden" name="merchant_id" value="1">
<input type="hidden" name="agreement_id" value="1">
<input type="hidden" name="order_id" value="0001">
<input type="hidden" name="amount" value="100">
<input type="hidden" name="currency" value="DKK">
<input type="hidden" name="continueurl" value="http://shop.domain.tld/continue">
<input type="hidden" name="cancelurl" value="http://shop.domain.tld/cancel">
<input type="hidden" name="callbackurl" value="http://shop.domain.tld/callback">
<input type="hidden" name="checksum" value="ed93f788f699c42aefa8a6713794b4d347ff493ecce1aca660581fb1511a1816">
<input type="submit" value="Continue to payment...">
</form>
Parameters
Parameter | Validation | Description | |
---|---|---|---|
R | version | /^v[\d]{1,}b?$/ |
The payment window version. Must currently be set to "v10". |
R | merchant_id | /^\d+$/ |
This is your Merchant Account id |
R | agreement_id | /^\d+$/ |
This is the User Agreement id. The checksum must be signed with the API-key belonging to this Agreement |
R | order_id | /^[a-zA-Z0-9]{4,20}$/ |
This is the order id generated in your system |
R | amount | /^[0-9]{1,9}$/ |
The order total amount in its smallest unit |
R | currency | /^[A-Z]{3}$/ |
The payment currency as the 3-letter ISO 4217 alphabetical code |
R | continueurl | !^https?://! |
The customer will be redirected to this URL upon a succesful payment. No data will be send to this URL. |
R | cancelurl | !^https?://! |
The customer will be redirected to this URL if the customer cancels the payment. No data will be send to this URL. |
O | callbackurl | !^https?://! |
Quickpay will make a call back to this URL with the result of the payment. Overwrites the default callback url. |
O | type | !^(payment|subscription)! |
Type of transaction. Defaults to payment |
language | /^[a-z]{2}$/ |
Set the language of the user interface. Defaults to English. | |
autocapture | /^[0-1]{1}$/ |
If set to 1, the payment will be captured automatically | |
autofee | /^[0-1]{1}$/ |
If set to 1, the fee charged by the acquirer will be calculated and added to the transaction amount | |
subscription | /^[0-1]{1}$/ |
DEPRECATED Create a subscription instead of a standard payment. Overrides type |
|
D | description | /^[\w\s\-\.]{1,20}$/ |
A value by the merchant's own choise. Used for identifying a subscription payment. Note: Required when 'subscribe' is set |
payment_methods | /^[a-zA-Z,\-]$/ |
Lock to some payment method(s). Multiple payment methods allowed by comma separation | |
acquirer | /^[a-z]+$/ |
Lock to a specific acquirer. | |
O | branding_id | /[^d]$/ |
Use this branding. Overwrites the default branding |
google_analytics_tracking_id | /[^d]$/ |
Your Google Analytics tracking ID | |
google_analytics_client_id | /[^d]$/ |
Your Google Analytics client ID | |
variables | Custom variables set on the created payment. Submit them as nested params: variables[myvar]=somevalue |
||
deadline | /^\d+$/ |
Deadline in seconds for the cardholder to complete the order. If deadline is reached, cardholder will be taken to cancelurl and a callback is sent. The operation type of the callback is deadline |
|
text_on_statement | Text that will be placed on cardholder’s bank statement (MAX 22 ASCII characters and only supported by Clearhaus currently). | ||
customer_email | Customer email address (Required for PayPal credit-card payments) | ||
invoice_address_selection | /^[0|1]$ |
Receive invoice address information from acquirer.
Will be available and fetchable on transaction upon authorization (Currently only MobilePay and PayPal) |
|
invoice_address[name] | Invoice - Name | ||
invoice_address[att] | Invoice - Attention | ||
invoice_address[street] | Invoice - Street | ||
invoice_address[house_number] | Invoice - House number (DEU and NLD) | ||
invoice_address[house_extension] | Invoice - House extension (NLD) | ||
invoice_address[zip_code] | Invoice - ZIP code | ||
invoice_address[city] | Invoice - City | ||
invoice_address[region] | Invoice - Region | ||
invoice_address[country_code] | Invoice - Country code (ISO-3166-1 Alpha 3) | ||
invoice_address[vat_no] | Invoice - VAT number | ||
invoice_address[phone_number] | Invoice - Phone number | ||
invoice_address[mobile_number] | Invoice - Mobile number | ||
invoice_address[email] | Invoice - Email address | ||
invoice_address_selection | /^[0|1]$ |
Receive shipping address information from acquirer.
Will be available and fetchable on transaction upon authorization (Currently only MobilePay and PayPal) |
|
shipping_address[name] | Shipping - Name | ||
shipping_address[att] | Shipping - Attension | ||
shipping_address[street] | Shipping - Street | ||
shipping_address[house_number] | Shipping - House number (DEU and NLD) | ||
shipping_address[house_extension] | Shipping - House extension (NLD) | ||
shipping_address[zip_code] | Shipping - ZIP code | ||
shipping_address[city] | Shipping - City | ||
shipping_address[region] | Shipping - Region | ||
shipping_address[country_code] | Shipping - Country code (ISO-3166-1 Alpha 3) | ||
shipping_address[vat_no] | Shipping - VAT number | ||
shipping_address[phone_number] | Shipping - Phone number | ||
shipping_address[mobile_number] | Shipping - Mobile number | ||
shipping_address[email] | Shipping - Email address | ||
basket[[0-9]+ ] |
Array of basket items | ||
basket[[0-9]+ ][qty] |
/^[0-9]+$/ |
Basket item quantity | |
basket[[0-9]+ ][item_no] |
Basket item number (SKU) | ||
basket[[0-9]+ ][item_name] |
Basket item Name | ||
basket[[0-9]+ ][item_price] |
/^[0-9]{1,9}$/ |
Basket item total price in its smallest unit (including VAT) | |
basket[[0-9]+ ][vat_rate] |
/^0\.[0-9]{2}$/ |
Basket item VAT rate (ex. 0.25 for 25%) | |
branding_config[enable_card_holder_field] | /^[0-1]{1}$/ |
If set to 1, the card holder can fill in their name in the payment window | |
branding_config[enable_3d_card_field] | /^[0-1]{1}$/ |
If set to 1, the card holder can choose to pay using 3D Secure. | |
branding_config[title] | Set title of payment window | ||
branding_config[autojump] | /^[0-1]{1}$/ |
It set to 1, the browser autojumps between input fields | |
shopsystem[name] | Shop system module name | ||
shopsystem[version] | Shop system module version | ||
R | checksum | /^[a-z0-9]{64}$/ |
The calculated checksum of your form data |
R = Required field
O = Overwrites standard/configured value
D = Depends on other fields
Checksum
The Quickpay Form employs a checksum mechanism to
- authenticate you and your system
- ensure that the data has not been tangled with
To calculate the checksum you must
- sort the request data key/value-pairs in the keys’ alphabetical order - All request data must be included in the checksum calculation
- concatenate the values (including empty values as empty strings) separated by a single space
- calculate the checksum by using HMAC with SHA256 as the cryptographic hash function. The HMAC is signed with a API key from one of your User Agreements - most likely the “Payment Window” system user.
The checksum is added to the request data. When Quickpay receives the request a checksum is calculated in the exact same way. If this checksum matches the one provided in the request data the processing of the request continues.
Note: The checksum is calculated only from Quickpay specific parameters. If you for some reason submit other parameters, those will not be part of the checksum.
Examples
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
require 'openssl'
def sign(params, api_key)
flattened_params = flatten_params(params)
values = flattened_params.sort.map { |_, value| value }
base = values.join(' ')
OpenSSL::HMAC.hexdigest('sha256', api_key, base)
end
def flatten_params(obj, result = {}, path = [])
case obj
when Hash
obj.each do |k, v|
flatten_params(v, result, [*path, k])
end
when Array
obj.each_with_index do |v, i|
flatten_params(v, result, [*path, i])
end
else
result[path.map{|p| "[#{p}]"}.join.to_sym] = obj
end
result
end
params = {
:version => "v10",
:merchant_id => 1,
:agreement_id => 1,
:order_id => "0001",
:amount => 100,
:currency => "DKK",
:continueurl => "http://shop.domain.tld/continue",
:cancelurl => "http://shop.domain.tld/cancel",
:callbackurl => "http://shop.domain.tld/callback",
:variables => {
:a => 'b',
:c => 'd'
}
}
params[:checksum] = sign(params, "your_secret_payment_window_api_key")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<?php
function sign($params, $api_key) {
$flattened_params = flatten_params($params);
ksort($flattened_params);
$base = implode(" ", $flattened_params);
return hash_hmac("sha256", $base, $api_key);
}
function flatten_params($obj, $result = array(), $path = array()) {
if (is_array($obj)) {
foreach ($obj as $k => $v) {
$result = array_merge($result, flatten_params($v, $result, array_merge($path, array($k))));
}
} else {
$result[implode("", array_map(function($p) { return "[{$p}]"; }, $path))] = $obj;
}
return $result;
}
$params = array(
"version" => "v10",
"merchant_id" => 1,
"agreement_id" => 1,
"order_id" => "0001",
"amount" => 100,
"currency" => "DKK",
"continueurl" => "http://shop.domain.tld/continue",
"cancelurl" => "http://shop.domain.tld/cancel",
"callbackurl" => "http://shop.domain.tld/callback",
);
$params["checksum"] = sign($params, "your_secret_payment_window_api_key");
?>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
use Digest::SHA qw(hmac_sha256_hex);
sub sign {
my ($params, $api_key) = @_;
my $base = join " ", @$params{ sort keys %$params };
hmac_sha256_hex($base, $api_key);
}
my $params = {
version => "v10",
merchant_id => 1,
agreement_id => 1,
order_id => "0001",
amount => 100,
currency => "DKK",
continueurl => "http://shop.domain.tld/continue",
cancelurl => "http://shop.domain.tld/cancel",
callbackurl => "http://shop.domain.tld/callback"
};
$params->{checksum} = sign($params, "your_secret_payment_window_api_key");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import hmac, hashlib, sys
PY3 = sys.version_info[0] >= 3
def sign(params, api_key):
items = sorted(params.items(), key=lambda x: x[0])
base = ' '.join([ str(pair[1]) for pair in items])
if PY3:
return hmac.new(
bytes(api_key, "utf-8"),
bytes(base, "utf-8"),
hashlib.sha256
).hexdigest()
else:
return hmac.new(api_key, base, hashlib.sha256).hexdigest()
params = dict(
version = "v10",
merchant_id = 1,
agreement_id = 1,
order_id = "0001",
amount = 100,
currency = "DKK",
continueurl = "http://shop.domain.tld/continue",
cancelurl = "http://shop.domain.tld/cancel",
callbackurl = "http://shop.domain.tld/callback"
)
params['checksum'] = sign(params, "your_secret_payment_window_api_key")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private string Sign(Dictionary<string, string> params, string api_key) {
var result = String.Join(" ", params.OrderBy(c => c.Key).Select(c => c.Value).ToArray());
var e = Encoding.UTF8;
var hmac = new HMACSHA256(e.GetBytes(api_key));
byte[] b = hmac.ComputeHash(e.GetBytes(result));
var s = new StringBuilder();
for (int i = 0; i < b.Length; i++)
{
s.Append(b[i].ToString("x2"));
}
return s.ToString();
}
public ActionResult QuickPay() {
var params = new Dictionary<string, string>();
params.Add("version", "v10");
params.Add("merchant_id", "1");
params.Add("agreement_id", "1");
params.Add("order_id", "0001");
params.Add("amount", "100");
params.Add("currency", "DKK");
params.Add("continueurl", "http://shop.domain.tld/continue");
params.Add("cancelurl", "http://shop.domain.tld/cancel");
params.Add("callbackurl", "http://shop.domain.tld/callback");
params.Add("language", "da");
params.Add("autocapture", "1");
ViewBag.Language = language;
ViewBag.Autocapture = autocapture;
ViewBag.OrderId = orderId;
ViewBag.MerchantId = merchantId;
ViewBag.AgreementId = agreementId;
ViewBag.Amount = amount;
ViewBag.Currency = currency;
ViewBag.ContinueUrl = continueUrl;
ViewBag.CancelUrl = cancelUrl;
ViewBag.CallbackUrl = callbackUrl;
ViewBag.Checksum = Sign(params, "your_secret_payment_window_api_key");
return View();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
const crypto = require('crypto');
function sign(params, api_key) {
var flattened_params = flatten_params(params);
var values = Object.keys(flattened_params).sort().map(key => flattened_params[key]).join(' ');
return crypto.createHmac('sha256', api_key).update(values).digest('hex');
}
function flatten_params(params, result, path) {
result = result || {};
path = path || [];
if (params instanceof Object) {
var k;
for (k in params) {
flatten_params(params[k], result, [...path, k]);
}
} else {
result[path.map(key => '[' + key + ']').join()] = params;
}
return result;
}
var params = {
version: 'v10',
merchant_id: 1,
agreement_id: 1,
amount: 100,
currency: 'DKK',
order_id: '0001',
callbackurl: 'http://shop.domain.tld/callback',
cancelurl: 'http://shop.domain.tld/cancel',
continueurl: 'http://shop.domain.tld/continue',
variables: {
a: 'b',
c: 'd'
}
};
params.checksum = sign(params, 'your_secret_payment_window_api_key');