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 |
<!-- 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_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) 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
Ruby
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") |
PHP
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"); ?> |
Perl
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"); |
Python
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") |
.NET
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(); } |
NodeJS
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'); |