Search docs

Are you looking for test card numbers?

Would you like to contact support?

Start searching Adyen's documentation...

  Documentation

Signing notifications with HMAC

Protect your server from unauthorised notifications.


Adyen notifications use mutual authentication over SSL in combination with basic authentication that you set up in your Customer Area. To verify that a notification was not modified during transmission, we strongly recommend that you additionally enable Hash-based Message Authentication Code (HMAC) signatures for notifications.

An HMAC signature is calculated using a request's key-value pairs and a secret key, which is known only to you and the Adyen payments platform. By verifying this signature, you'll confirm that the notification was not modified during transmission.

Enable HMAC signatures

To enable HMAC signed notifications, you'll need to generate an HMAC key:

  1. Sign in to your Customer Area, and go to SettingsServer Communication.
  2. For Standard Notification, click Edit & Test.
  3. Under Additional Settings, click  Generate New HMAC key. Copy down your HMAC key. You'll use it to verify HMAC signatures.
  4. Click Save Configuration.

You'll now receive Standard notifications that have been signed with your HMAC key.

If you generate a new HMAC key, it might take some time to propagate this in our infrastructure, so make sure that you can still accept notifications signed with your previous HMAC key for some time.

Verify HMAC signature

You can find a notification's HMAC signature in hmacSignature, contained within its additionalData.

HMAC signatures are calculated using the following key-value pairs:

Key Example
pspReference 7914073381342284
originalReference  
merchantAccountCode TestMerchant
merchantReference TestPayment-1407325143704
amount.value 1130
amount.currency EUR
eventCode AUTHORISATION
success true

Signature strings are constructed in the order:

pspReference:originalReference:merchantAccountCode:merchantReference:value:currency:eventCode:success

Any fields that are empty will have the value of an empty string. For example, when the originalReference is missing the HMAC signature is constructed with the string: 

7914073381342284::TestMerchant:TestPayment-1407325143704:1130:EUR:AUTHORISATION:true

To calculate the HMAC signature for a notification:

import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.junit.Test;

public class NotificationHmacExample {
    private static final char SEPARATOR_CHAR = ':';
    @
    Test
    public void testNotificationHmac() {
        // Example HEX Key (set in customer portal under: 
        // Settings -> Server Communication -> Standard Notification 
        String keyHex = "009E9E92268087AAD241638D3325201AFC8AAE6F3DCD369B6D32E87129FFAB10";
        // hmacSignature can be found in additionalData.get("hmacSignature") 
        final String hmacSignature = "c5sF0nZAqbyJTzy4OGl4Jij8XyDJwiNpVkU79KT5vTQ=";
        // Example data 
        String pspReference = "7914073251449896";
        String originalReference = "";
        String merchantAccountCode = "TestMerchant";
        String merchantReference = "TestPayment-1407325143704";
        Amount amt = new Amount(1130, "EUR");
        String eventCode = "AUTHORISATION";
        boolean success = true;
        StringBuilder payloadToSign = new StringBuilder();
        if (pspReference != null) {
            payloadToSign.append(pspReference);
        }
        payloadToSign.append(SEPARATOR_CHAR);
        if (originalReference != null) {
            payloadToSign.append(originalReference);
        }
        payloadToSign.append(SEPARATOR_CHAR);
        if (merchantAccountCode != null) {
            payloadToSign.append(merchantAccountCode);
        }
        payloadToSign.append(SEPARATOR_CHAR);
        if (merchantReference != null) {
            payloadToSign.append(merchantReference);
        }
        payloadToSign.append(SEPARATOR_CHAR);
        if (amt == null) {
            payloadToSign.append(SEPARATOR_CHAR);
            payloadToSign.append(SEPARATOR_CHAR);
        } else {
            payloadToSign.append(Long.toString(amt.getValue()));
            payloadToSign.append(SEPARATOR_CHAR);
            payloadToSign.append(amt.getCurrency());
            payloadToSign.append(SEPARATOR_CHAR);
        }
        if (eventCode != null) {
            payloadToSign.append(eventCode);
        }
        payloadToSign.append(SEPARATOR_CHAR);
        payloadToSign.append(success ? "true" : "false");
        Base64 base64 = new Base64();
        try {
            // decode HEX Key into bytes 
            byte[] keyBytes = Hex.decodeHex(keyHex.toCharArray());
            // compile the payload to sign 
            String payloadString = payloadToSign.toString();
            // get payload in bytes 
            byte[] payload = payloadString.getBytes("UTF-8");
            // instantiate the MAC object using HMAC / SHA256 
            Mac hmacSha256 = javax.crypto.Mac.getInstance("HmacSHA256");
            // create a key object using the secret key and MAC object 
            SecretKey secretKey = new SecretKeySpec(keyBytes, hmacSha256.getAlgorithm());
            // initialise the MAC object 
            hmacSha256.init(secretKey);
            // finalise the MAC operation 
            byte[] signedPayload = hmacSha256.doFinal(payload);
            // encode the signed payload in Base64 
            byte[] encodedSignedPayload = base64.encode(signedPayload);
            System.out.println("original HMAC signature: " + hmacSignature);
            System.out.println("computed HMAC signature: " + new String(encodedSignedPayload, "ASCII"));
            // assert the calculated Base64 encoded HMAC is equal to the received Base64 encoded HMAC 
            assertTrue(Arrays.equals(encodedSignedPayload, hmacSignature.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException e) {
            // HmacSHA256 should be supported 
        } catch (DecoderException e) {
            // Check key for odd number or characters outside of HEX (base16) 
        } catch (InvalidKeyException e) {
            // The key is invalid 
        } catch (UnsupportedEncodingException e) {
            // UTF-8 should be supported 
        }
    }
}

If the calculated hmacSignature matches the value you received in the notification, the notification wasn't modified during transmission.

HMAC signature examples

The following are JSON, SOAP, and FORM examples of a notification containing an HMAC signature:

{  
   "live":"false",
   "notificationItems":[  
      {  
         "NotificationRequestItem":{  
            "additionalData":{  
               "hmacSignature":"+JWKfq4ynALK+FFzGgHnp1jSMQJMBJeb87dlph24sXw="
            },
            "amount":{  
               "value":1130,
               "currency":"EUR"
            },
            "pspReference":"7914073381342284",
            "eventCode":"AUTHORISATION",
            "eventDate":"2014-08-06T17:15:34.121+02:00",
            "merchantAccountCode":"TestMerchant",
            "operations":[  
               "CANCEL",
               "CAPTURE",
               "REFUND"
            ],
            "merchantReference":"TestPayment-1407325143704",
            "paymentMethod":"visa",
            "success":"true"
         }
      }
   ]
}
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soap:Body>
      <ns1:sendNotification xmlns:ns1="http://notification.services.adyen.com">
         <ns1:notification>
            <live xmlns="http://notification.services.adyen.com">false</live>
            <notificationItems xmlns="http://notification.services.adyen.com">
               <notificationRequestItem>
                  <additionalData>
                     <entry>
                        <key xsi:type="xsd:string">hmacSignature</key>
                        <value xsi:type="xsd:string">+JWKfq4ynALK+FFzGgHnp1jSMQJMBJeb87dlph24sXw=</value>
                     </entry>
                  </additionalData>
                  <amount>
                     <currency xmlns="http://common.services.adyen.com">EUR</currency>
                     <value xmlns="http://common.services.adyen.com">1130</value>
                  </amount>
                  <eventCode>AUTHORISATION</eventCode>
                  <eventDate>2014-08-06T17:15:34.121+02:00</eventDate>
                  <merchantAccountCode>TestMerchant</merchantAccountCode>
                  <merchantReference>TestPayment-1407325143704</merchantReference>
                  <operations>
                     <string>CANCEL</string>
                     <string>CAPTURE</string>
                     <string>REFUND</string>
                  </operations>
                  <originalReference xsi:nil="true" />
                  <paymentMethod>visa</paymentMethod>
                  <pspReference>7914073381342284</pspReference>
                  <success>true</success>
               </notificationRequestItem>
            </notificationItems>
         </ns1:notification>
      </ns1:sendNotification>
   </soap:Body>
</soap:Envelope>
eventDate=2014-08-06T15%3A14%3A47.71Z&originalReference=0234567891123456&merchantReference=TestPayment-1407325143704&additionalData.hmacSignature=kfQO6cj64G9FGICJVozUx8xhp38ktwZJfAuYT%2BSA2Vc%3D&currency=EUR 
&pspReference=1234567890123456&merchantAccountCode=TestMerchant&eventCode=AUTHORISATION&value=1130 
&operations=CANCEL%2CCAPTURE%2CREFUND&success=true&paymentMethod=visa&live=false