Docs play_arrow X-Pay Token

API Key – Shared Secret (X-Pay-Token)

Some Visa Developer APIs require an API Key-Shared Secret Authenticationwhich Visa refers to as x-pay-token. To invoke an API using x-pay-token, you will need an API Key and a Shared Secret, which is provided on the project details page.

Note: The x-pay-token used by Visa Checkout is slightly different than the x-pay-token described in this section. For more information, refer to API Key – Shared Secret (x-pay-token) for Visa Checkout.

X-Pay Token Tutorial Video

Generating the X-Pay-Token

To successfully invoke your Visa Developer APIs, which use x-pay-token, your project must include the following:

  1. Add the API Key as the query parameter.
  2. Include the Accept and X-Pay-Token in the request header as shown in the sample below.

    Field Value
    Accept application/json
    X-PAY-TOKEN x-pay-token*

    Note: Refer to the section below on how to generate the x-pay-token value with SHA256 HMAC.

    Sample Header

    GET /vdp/helloworld?apikey=KSKDFJOP934ALSFDJP34 HTTP/1.0
    Host: sandbox.api.visa.com
    Accept: application/json
    X-PAY-TOKEN: xv2:1455716783:f5d15ed23f825ac69cd42e6fa187a175ecf7e9566ce4f21e11bad49bed4cc363

  3. Request payload. Include any resource-specific request parameters in the request payload before you make a request.
  4. Test different scenarios using the test data provided on the Project dashboard.

Generating the X-Pay-Token

To generate the x-pay-token, follow these steps:

  1. Generate a message string by concatenating the following parameters:
    message = timestamp + resource_path + query_string + request_body

    Note: For some products the context path is skipped while computing x-pay-token:
    Parameters Description
    timestamp This is the current timestamp in UTC (in seconds).
    resource_path This is the API endpoint you would like to invoke after the context path.
    Note: For some products the context path is skipped while computing x-pay-token.
    Product Part of the URL to be skipped while computing x-pay token Example
    Request URL Path to be used in x-pay-token calculation
    CyberSource /cybersource/ https://sandbox.api.visa.com/cybersource/payments/v1/authorizations payments/v1/authorizations
    Visa Checkout /wallet-services-web/ https://sandbox.api.visa.com/wallet-services-web/payment/data/{callId} payment/data/{callId}
    Visa Token Service   https://sandbox.api.visa.com/vts/provisionedTokens vts/provisionedTokens
    Visa Token Service Provisioning and Lifecycle Management   https://sandbox.api.visa.com/vtis/v1/pan/lifecycle vtis/v1/pan/lifecycle
    VDP Hello World /vdp/ https://sandbox.api.visa.com/vdp/helloworld helloworld
    query_string The apikey is a required query parameter. Query parameters should be in lexicographical order.
    request_body This is the API endpoint specific request body string.
  2. Create the x-pay-token, as shown below:

    XPayToken = "xv2:"+ timestamp + ":" + SHA256HMAC(shared_secret, message)

Note: The shared_secret is the shared secret from the Project dashboard.

 

Constructing the HTTP Header


Depending on your system needs, Visa Developer APIs will allow you to setup one or more HTTP header variables as illustrated in the following table.

Variable Name Value
Content-Type Optional

Specify request format

• XML Use text/xml

• JSON Use application/json

If not specified, expects JSON.
Accept Optional

Specify request format

• XML Use text/xml

• JSON Use application/json

If not specified, defaults to request format.

 

Testing X-Pay-Token Connectivity Using SOAPUI

SOAPUI is a free and open source Web Service Functional Testing solution. With an easy-to-use graphical user interface, SOAP UI allows you to rapidly create and execute web service API functional tests. It is highly recommended that you use SOAP UI, or a similar connectivity tool, to establish your initial connection to the Visa Developer sandbox.

Note: Prior to working with SOAPUI, you must Register and create a project that uses x-pay-token as an authentication service. Make sure that you have a valid API key and shared secret (available on Project dashboard).

SOAPUI REST project

  1. Download SoapUI 5.4 from https://www.soapui.org.
  2. Once installed, open SOAPUI and select File > New REST Project.
    Use the following URI: https://sandbox.api.visa.com/vdp/helloworld?apikey=<value of your API key> (replace the value of API key query string parameter with the actual API key that you received from the Visa Developer Platform).

    SOAP_UI_Testing

  3. Once the project is created, in project navigator, right click the URI, and select Generate TestSuite. Specify name for your test suite and click OK.

    Generate Test Suite

  4. In the project navigator, fully expand the newly created test suite and locate the test steps.
  5. Right click Test Steps, select Add Step, then select Groovy Script as shown below. Specify name for your script and click OK.

    SOAP UI Groovy Script
  6. Paste the following contents into the script body. Make sure to replace the API key and the shared secret with your own values from the Visa Developer Center.
    Run the script (by clicking the green chevron) and make sure that the value of x-pay-token is visible in the Log Output window.

    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    def hmac(String secretKey, String data) {
    Mac mac = Mac.getInstance("HmacSHA256")
    SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256")
    mac.init(secretKeySpec)
    byte[] digest = mac.doFinal(data.getBytes())
    return digest
    }
    def APIKey = ‘VALUE_OF_YOUR_API_KEY’
    def sharedSecret = ‘VALUE_OF_YOUR_SHARED_SECRET’
    def URI = "helloworld"
    def QS = "apikey="+APIKey
    def timeStampUTC = String.valueOf(System.currentTimeMillis().intdiv(1000L))
    def payload = ""
    def HMACDigest = hmac(sharedSecret, timeStampUTC + URI + QS + payload)
    def encodedDigest = HMACDigest.encodeHex().toString()
    def XPayToken = "xv2:"+ timeStampUTC + ":" + encodedDigest
    testRunner.testCase.setPropertyValue("xpayToken", XPayToken)
    log.info(XPayToken)

    Groovy Code

  7. Double click Request 1 (the test step just above your new, for example: "groovy" script). Select Headers tab and click the green plus sign to add a new header.

    SOAP XPayToken

  8. Add a custom header for the x-pay-token. The value of this header is set dynamically, when you run the script.

    Note: 
    You will need to use the following as the header value: ${#TestCase#xpayToken}.
    The header name will be static, and should be set to: x-pay-token. The resulting header setting will appear, as follows.

    SOAP XPayToken

  9. Run your test suite by first executing the script (by clicking the green chevron), and secondly by sending the test request (green chevron on the request page). If all is correct, you should see the current timestamp in the response.

  10. Run Groovy Script

Sample Code for API Key – Shared Secret (X-Pay-Token)

Copied to clipboard
import java.math.BigInteger;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.SignatureException;


public static String generateXpaytoken(String resourcePath, String queryString, String requestBody, String sharedSecret) throws SignatureException {  
    String timestamp = timeStamp();  
    String beforeHash = timestamp + resourcePath + queryString + requestBody;
    String hash = hmacSha256Digest(beforeHash, sharedSecret);  
    String token = "xv2:" + timestamp + ":" + hash;  
    return token;  
}  

private static String timeStamp() {  
        return String.valueOf(System.currentTimeMillis()/ 1000L);  
    }  

private static String hmacSha256Digest(String data, String sharedSecret)  
        throws SignatureException {  
    return getDigest("HmacSHA256", sharedSecret, data, true);  
}  

private static String getDigest(String algorithm, String sharedSecret, String data,  boolean toLower) throws SignatureException {  
    try {  
        Mac sha256HMAC = Mac.getInstance(algorithm);  
        SecretKeySpec secretKey = new SecretKeySpec(sharedSecret.getBytes(StandardCharsets.UTF_8), algorithm);  
        sha256HMAC.init(secretKey);  

        byte[] hashByte = sha256HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));  
        String hashString = toHex(hashByte);  

        return toLower ? hashString.toLowerCase() : hashString;
    } catch (Exception e) {  
        throw new SignatureException(e);  
    }  
}  

private static String toHex(byte[] bytes) {  
    BigInteger bi = new BigInteger(1, bytes);  
    return String.format("%0" + (bytes.length << 1) + "X", bi);  
}