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.

Please note! The recommended payment integration is Quickpay Link

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
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
Shipping 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
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
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
Shop system
shopsystem[name] Shop system module name
shopsystem[version] Shop system module version
Checksum
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');