Message Signature

When calling our APIs you will often find you need to create a Message-Signature. This is a combination of your API Key, a ClientRequestId, the time and the body of your request. We recommend you follow the linked recipe below to get a feel for how it is used. The rest of this page goes into more detail about it.

Example

A standard API call to execute a Primary Transaction in our Payments API might look like this:

{
    method: "POST",
    url: "https://prod.emea.api.fiservapps.com/sandbox/ipp/payments-gateway/v2/payments/",
    headers: {
      "Content-Type": "application/json",
      "Client-Request-Id": "Client request ID goes here",
      "Api-Key": "API Key goes here",
      "Timestamp": "Date().getTime() goes here",
      "Message-Signature": "Message Signature goes here"
    },
    body: JSON.stringify({
      requestType: "PaymentCardSaleTransaction",
      transactionAmount: { total: "13", currency: "GBP" },
      paymentMethod: {
        paymentCard: {
          number: "4012000000000001",
          securityCode: "123",
          expiryDate: { month: "01", year: "29" }
        },
      },
      authenticationRequest: {
        authenticationType: "Secure3D21AuthenticationRequest",
        termURL: "http://localhost:3124/api/v1/payments/3ds",
        challengeIndicator: "04"
      },
    })
  }

Variables

API-Key

You can retrieve this key from the Developer Portal

Client-Request-Id

This is generated by you the client of our API. It is a unique ID that is returned to you as part of the response. You can generate it like this:

var ClientRequestId = uuidv4();

Time

The getTime() method returns the number of milliseconds since the Unix Epoch. The Unix epoch is the time 00:00:00 UTC on 1 January 1970.

var time = new Date().getTime();

Request body

The request body must be stringified.

var requestBody = JSON.stringify(body);

Message-Signature

All of the variables above need to be available for the Message-Signature to be generated.

Generate the rawSignature first:

var rawSignature = apiKey + ClientRequestId + time + requestBody;

Create a HMAC using CryptoJS

var computedHash = CryptoJS.algo.HMAC.create(
    CryptoJS.algo.SHA256,
    secret.toString()
);

🚧

Secret Key

You can retrieve this secret key from the Developer Portal Apps screen. It must be the from the same application as your API Key.

Update your computedHash with your rawSignature

computedHash.update(rawSignature);
computedHash = computedHash.finalize();
var messageSignature = CryptoJS.enc.Base64.stringify(computedHash);

That's it, add the messageSignature into your header.

Demo app

We have a demo app available here which has the above code.

Example of code

//These libraries are for the running of this API.
const express = require("express");
const router = express.Router();
var request = require("request");
var CryptoJS = require("crypto-js");
const {v4: uuidv4} = require("uuid");

//These are the API keys and token for generating an encrypted message
const key = "API Key goes here";
const secret = "Secret goes here";
const url = "https://prod.emea.api.fiservapps.com/sandbox/ipp/payments-gateway/v2/payments/"

//When ever you communicate with IPG you need to encrypt the body of the message. This function modifies the API call to include the correct message signatures. 
function fiservEncode(method, url, body, callback) {
  var ClientRequestId = uuidv4();
  var time = new Date().getTime();
  var requestBody = JSON.stringify(body);
  if(method === 'GET') {
    requestBody = '';
  }  
  var rawSignature = key + ClientRequestId + time + requestBody;
  var computedHash = CryptoJS.algo.HMAC.create(
    CryptoJS.algo.SHA256,
    secret.toString()
  );
  computedHash.update(rawSignature);
  computedHash = computedHash.finalize();
  var computedHmac = CryptoJS.enc.Base64.stringify(computedHash);

  var options = {
    method: method,
    url,
    headers: {
      "Content-Type": "application/json",
      "Client-Request-Id": ClientRequestId,
      "Api-Key": key,
      Timestamp: time,
      "Message-Signature": computedHmac
    },
    body: JSON.stringify(body),
  };


    callback(options);

}

//Step 2: Create Primary Transaction (Only performs a standard payment that requests 3DSecure!)
router.post("/payments", async (req, res) => {
  //Start by encoding the message.
  fiservEncode(
    "POST",
    url,
    {
      requestType: "PaymentCardSaleTransaction",
      transactionAmount: { total: "13", currency: "GBP" },
      paymentMethod: {
        paymentCard: {
          number: req.body.cardNumber,
          securityCode: req.body.securityCode,
          expiryDate: { month: req.body.expiryMonth, year: req.body.expiryYear },
        },
      },
      authenticationRequest: {
        authenticationType: "Secure3D21AuthenticationRequest",
        termURL: "http://localhost:3124/api/v1/payments/3ds",
        challengeIndicator: "04", // This indicates what type of transaction we would like. 
      },
    },
    (options) => {
      //Submit the API call to Fiserv
      request(options, function (error, paymentResponse) {
        if (error) throw new Error(error);
        let paymentData = JSON.parse(paymentResponse.body);
        return res.status(200).json({
          requestName: "Payment POST - Creating the payment request",
          ...paymentData
        });
      });
    }
  );
});

Want a quick overview?