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');