Sample code for 30+ languages & platforms
Dart

Adyen HMAC Signature Calculation for Hosted Payment Pages

See more Adyen Examples

Demonstrates how to do the HMAC Signature Calculation for a hosted payment page (HPP) in Adyen.

For a C# ASP.NET Razor Pages example showing the HTML Form with HMAC signature code, see Adyen HMAC Signature Calculation in C#

Chilkat Dart Downloads

Dart
import 'package:chilkat/chilkat.dart';

void main() {
  // This example requires the Chilkat API to have been previously unlocked.
  // See Global Unlock Sample for sample code.

  final strHtml = '<table class="od"><tr><th>Description</th><th>Quantity</th><th>Amount</th></tr><tr><td>1 Digital Camera</td><td class="r">1</td><td class="r">100 GBP</td></tr><tr><td class="b">Total</td><td class="r"></td><td class="b r">100.00 GBP</td></tr></table>';

  final gzip = CkGzip();
  final gzOrderData = gzip.compressStringENC(strHtml, 'utf-8', 'base64');

  final xml = CkXml();
  xml.tag = 'keyValuePairs';

  xml.newChild2('orderData', gzOrderData);

  // required, The payment deadline; the payment needs to occur within the specified time value.
  final sessionValidity = '2019-08-11T10:30:00Z';
  xml.newChild2('sessionValidity', sessionValidity);

  // optional.  Normally we'll let Adyen automatically know the country based on the IP address.
  // By default, the payment methods offered to a shopper are filtered based on the country the shopper's IP address is mapped to. 
  // In this way, shoppers are not offered payment methods that are not available in the country they are carrying out the transaction from. 
  // This IP-to-country mapping is not 100% accurate, so if you have already established the country of the shopper, you can set it explicitly 
  // in the countryCode parameter.
  final countryCode = 'GB';
  xml.newChild2('countryCode', countryCode);

  // optional
  final shopperLocale = 'en_GB';
  // If not specified, the locale preference is set to en_GB   by default.
  // When it is not necessary to include the country-specific part, use only the language code.
  // For example: it instead of it_IT to set the locale preferences to Italian.
  xml.newChild2('shopperLocale', shopperLocale);

  // required, A reference to uniquely identify the payment. This reference is used in all communication with you about the payment status. 
  // We recommend using a unique value per payment; however, it is not a requirement. If you need to provide multiple references for a transaction, 
  // you can enter them in this field. Separate each reference value with a hyphen character ("-"). This field has a length restriction: 
  // you can enter max. 80 characters.
  final merchantReference = 'paymentTest1234';
  xml.newChild2('merchantReference', merchantReference);

  // required, The merchant account identifier you want to process the (transaction) request with.
  final merchantAccount = 'ChilkatSoftwareIncCOM';
  xml.newChild2('merchantAccount', merchantAccount);

  // required.  10000 for $100.00
  final paymentAmount = '10000';
  xml.newChild2('paymentAmount', paymentAmount);

  // required, The three-character ISO currency code
  final currencyCode = 'GBP';
  xml.newChild2('currencyCode', currencyCode);

  // required.
  final skinCode = 'S7uWsvfB';
  xml.newChild2('skinCode', skinCode);

  // optional, A unique identifier for the shopper, for example, a customer ID.
  // We recommend providing this information, as it is used in velocity fraud checks. It is also the key in recurring payments.
  // This field is mandatory in recurring payments.  
  final shopperReference = 'somebody@example.com';
  xml.newChild2('shopperReference', shopperReference);

  // optional
  final shopperEmail = 'somebody@example.com';
  xml.newChild2('shopperEmail', shopperEmail);

  // optional, An integer value that adds up to the normal fraud score.
  // The value can be either a positive or negative integer.
  xml.newChild2('offset', '0');

  // Apparently this is a required field.
  final shipBeforeDate = '2019-06-04';
  xml.newChild2('shipBeforeDate', shipBeforeDate);

  xml.sortByTag(true);

  // Encode...
  //  "\" (backslash) as "\\"
  //  ":" (colon) as "\:"

  final sbTags = CkStringBuilder();
  final sbValues = CkStringBuilder();

  final sbContent = CkStringBuilder();
  final n = xml.numChildren;
  var i = 0;
  while (i < n) {
    if (i > 0) {
      sbTags.append(':');
      sbValues.append(':');
    }

    xml.getChild2(i);
    sbTags.append(xml.tag);

    sbContent.setString(xml.content);
    var numReplaced = sbContent.replace('\\', '\\\\');
    numReplaced = sbContent.replace(':', '\\:');
    sbValues.appendSb(sbContent);
    xml.getParent2();

    i++;
  }

  final sbSigningStr = CkStringBuilder();
  sbSigningStr.appendSb(sbTags);
  sbSigningStr.append(':');
  sbSigningStr.appendSb(sbValues);

  final crypt = CkCrypt2();
  crypt.hashAlgorithm = 'sha256';
  crypt.macAlgorithm = 'hmac';

  final hmacKey = '934D1E806DDD99595EB430076FD7F8E4D12D0A3F51243A4C0C3897703118E739';
  crypt.setMacKeyEncoded(hmacKey, 'hex');

  crypt.encodingMode = 'base64';
  final merchantSig = crypt.macStringENC(sbSigningStr.getAsString());

  print(merchantSig);
}