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 any acquirer specific requirements.

Simple example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!--
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">
-->
<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[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
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%)
R checksum /^[a-z0-9]{64}$/ The calculated checksum of your form data

Symbols

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) seperated 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
36
37
38
39
<?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",
  "variables"   => array(
    "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
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();
}