Hi Visa Developer Support,
I am experiencing an issue when testing the Visa In-App Provisioning API using SOAPUI. Despite following the official documentation, I consistently receive a 401 Token Validation Failed error.
HTTP Request (RAW Output from SOAPUI)
POST https://sandbox.api.visa.com/inapp/provisioning/cardData/applePay?apiKey=8D2NG8AP36GFENNJPKOJ21Ni0pq... HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: application/json
x-pay-token: xv2:1738829799:4d52a6449a6b1cb326da89a37fba5e6e38eaae756a050674d0f6071860f3d66d
Content-Length: 1636
Host: sandbox.api.visa.com
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.5.5 (Java/17.0.12)
{
"deviceCert": "MIID/TCCA6OgAwIBAgIIMq/qUa9Z2nMwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xODA2MDEyMjAzMTBaFw0yMDA2MzAyMjAzMTBaMGwxNTAzBgNVBAMMLGVjYy1jcnlwdG8tc2VydmljZXMtZW5jaXBoZXJtZW50X1VDNi1TQU5EQk9YMREwDwYDVQQLDAhBcHBsZVBheTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATGiJjmEMmvOZBGj+tdj2ED7xnc9y1C0vNVaqZva7lvKkbgrfcWdo0/NdIJZ5wDcZ0eBtPuRJ+q/eSP9FLXQ19wo4ICGDCCAhQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSEtoTMOoZichZZlOgao71I3zrfCzBHBggrBgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGV3d2RyY2EyMDUwggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxld3dkcmNhMi5jcmwwHQYDVR0OBBYEFMNruSHk5gH1LauD+wBI/9sgl/VpMA4GA1UdDwEB/wQEAwIDKDASBgkqhkiG92NkBicBAf8EAgUAMAoGCCqGSM49BAMCA0gAMEUCIQDhL+sL9bcrvAVO3UvswA805EHujfL7iVDrbEuJfOSJoAIgBPKehtuILl9x/SJ5kxReiml1zkJqUB8nTy0UOfUNIIQ=",
"nonce": "kauVuA==",
"nonceSignature": "QHuLYArUCO2OZevP0rHc99g9RJp4O1dgsZuVpUdlA7zPWqCDhVQo9Mxr1uPS6GVyjZYo3YElIhHRV4Mv3wEJ3hGOaxK1gResup88QWDK1fL0",
"tokenServiceProvider": "V",
"vcardId": "v-123-f98b91af-77c9-4e78-a1fe-345268939401"
}
HTTP Response (RAW Output)
{"responseStatus": {
"status": 401,
"code": "9159",
"severity": "ERROR",
"message": "Token Validation Failed",
"info": ""
}}
GROOVY SCRIPT
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import groovy.json.JsonOutput
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 = '8D2NG8AP36GFENNJPKOJ21Ni0pqrsjld6xnyYRy5v7Xm5RKxU'
def sharedSecret = '{Khmk$aa-hTj6X6YNfPuee5{21KHodAmCYB/#E7h'
def URI = "inapp/provisioning/cardData/applePay"
def QS = "apiKey="+APIKey
def timeStampUTC = String.valueOf(System.currentTimeMillis().intdiv(1000L))
def jsonPayload = [
deviceCert: "MIID/TCCA6OgAwIBAgIIMq/qUa9Z2nMwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZX...",
nonce: "kauVuA==",
nonceSignature: "QHuLYArUCO2OZevP0rHc99g9RJp4O1dgsZuVpUdlA7zPWqCDhVQo9Mxr1uPS6GVyjZYo3YElIhHRV4Mv3wEJ3hGOaxK1gResup88QWDK1fL0",
tokenServiceProvider: "V",
vcardId: "v-123-f98b91af-77c9-4e78-a1fe-345268939401"
]
def payload = JsonOutput.toJson(jsonPayload)
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)
Request Body (JSON Payload)
{ "deviceCert": "MIID/TCCA6OgAwIBAgIIMq/qUa9Z2nMwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xODA2MDEyMjAzMTBaFw0yMDA2MzAyMjAzMTBaMGwxNTAzBgNVBAMMLGVjYy1jcnlwdG8tc2VydmljZXMtZW5jaXBoZXJtZW50X1VDNi1TQU5EQk9YMREwDwYDVQQLDAhBcHBsZVBheTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATGiJjmEMmvOZBGj+tdj2ED7xnc9y1C0vNVaqZva7lvKkbgrfcWdo0/NdIJZ5wDcZ0eBtPuRJ+q/eSP9FLXQ19wo4ICGDCCAhQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSEtoTMOoZichZZlOgao71I3zrfCzBHBggrBgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGV3d2RyY2EyMDUwggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxld3dkcmNhMi5jcmwwHQYDVR0OBBYEFMNruSHk5gH1LauD+wBI/9sgl/VpMA4GA1UdDwEB/wQEAwIDKDASBgkqhkiG92NkBicBAf8EAgUAMAoGCCqGSM49BAMCA0gAMEUCIQDhL+sL9bcrvAVO3UvswA805EHujfL7iVDrbEuJfOSJoAIgBPKehtuILl9x/SJ5kxReiml1zkJqUB8nTy0UOfUNIIQ=", "nonce": "kauVuA==", "nonceSignature": "QHuLYArUCO2OZevP0rHc99g9RJp4O1dgsZuVpUdlA7zPWqCDhVQo9Mxr1uPS6GVyjZYo3YElIhHRV4Mv3wEJ3hGOaxK1gResup88QWDK1fL0", "tokenServiceProvider": "V", "vcardId": "v-123-f98b91af-77c9-4e78-a1fe-345268939401" }
here is the export .xml
https://sandbox.api.visa.comapiKey8D2NG8AP36GFENNJPKOJ21Ni0pqrsjld6xnyYRy5v7Xm5RKxUQUERY8D2NG8AP36GF... 401app:Faultapplication/json<xml-fragment/>https://sandbox.api.visa.com{ "deviceCert": "MIID/TCCA6OgAwIBAgIIMq/qUa9Z2nMwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xODA2MDEyMjAzMTBaFw0yMDA2MzAyMjAzMTBaMGwxNTAzBgNVBAMMLGVjYy1jcnlwdG8tc2VydmljZXMtZW5jaXBoZXJtZW50X1VDNi1TQU5EQk9YMREwDwYDVQQLDAhBcHBsZVBheTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATGiJjmEMmvOZBGj+tdj2ED7xnc9y1C0vNVaqZva7lvKkbgrfcWdo0/NdIJZ5wDcZ0eBtPuRJ+q/eSP9FLXQ19wo4ICGDCCAhQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSEtoTMOoZichZZlOgao71I3zrfCzBHBggrBgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGV3d2RyY2EyMDUwggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxld3dkcmNhMi5jcmwwHQYDVR0OBBYEFMNruSHk5gH1LauD+wBI/9sgl/VpMA4GA1UdDwEB/wQEAwIDKDASBgkqhkiG92NkBicBAf8EAgUAMAoGCCqGSM49BAMCA0gAMEUCIQDhL+sL9bcrvAVO3UvswA805EHujfL7iVDrbEuJfOSJoAIgBPKehtuILl9x/SJ5kxReiml1zkJqUB8nTy0UOfUNIIQ=", "nonce": "kauVuA==", "nonceSignature": "QHuLYArUCO2OZevP0rHc99g9RJp4O1dgsZuVpUdlA7zPWqCDhVQo9Mxr1uPS6GVyjZYo3YElIhHRV4Mv3wEJ3hGOaxK1gResup88QWDK1fL0", "tokenServiceProvider": "V", "vcardId": "v-123-f98b91af-77c9-4e78-a1fe-345268939401" } https://sandbox.api.visa.com/inapp/provisioning/cardData/applePayNo AuthorizationapiKeyTestSuite generated for REST Service [https://sandbox.api.visa.com]SEQUENTIALTestCase generated for REST Resource [ApplePay] located at [/inapp/provisioning/cardData/applePay]<entry key="x-pay-token" value="${#TestCase#xpayToken}" xmlns="http://eviware.com/soapui/config"/>https://sandbox.api.visa.com{ "deviceCert": "MIID/TCCA6OgAwIBAgIIMq/qUa9Z2nMwCgYIKoZIzj0EAwIwgYAxNDAyBgNVBAMMK0FwcGxlIFdvcmxkd2lkZSBEZXZlbG9wZXIgUmVsYXRpb25zIENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzAeFw0xODA2MDEyMjAzMTBaFw0yMDA2MzAyMjAzMTBaMGwxNTAzBgNVBAMMLGVjYy1jcnlwdG8tc2VydmljZXMtZW5jaXBoZXJtZW50X1VDNi1TQU5EQk9YMREwDwYDVQQLDAhBcHBsZVBheTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATGiJjmEMmvOZBGj+tdj2ED7xnc9y1C0vNVaqZva7lvKkbgrfcWdo0/NdIJZ5wDcZ0eBtPuRJ+q/eSP9FLXQ19wo4ICGDCCAhQwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBSEtoTMOoZichZZlOgao71I3zrfCzBHBggrBgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAGGK2h0dHA6Ly9vY3NwLmFwcGxlLmNvbS9vY3NwMDMtYXBwbGV3d2RyY2EyMDUwggEdBgNVHSAEggEUMIIBEDCCAQwGCSqGSIb3Y2QFATCB/jCBwwYIKwYBBQUHAgIwgbYMgbNSZWxpYW5jZSBvbiB0aGlzIGNlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBhc3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFyZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRlIHBvbGljeSBhbmQgY2VydGlmaWNhdGlvbiBwcmFjdGljZSBzdGF0ZW1lbnRzLjA2BggrBgEFBQcCARYqaHR0cDovL3d3dy5hcHBsZS5jb20vY2VydGlmaWNhdGVhdXRob3JpdHkvMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwuYXBwbGUuY29tL2FwcGxld3dkcmNhMi5jcmwwHQYDVR0OBBYEFMNruSHk5gH1LauD+wBI/9sgl/VpMA4GA1UdDwEB/wQEAwIDKDASBgkqhkiG92NkBicBAf8EAgUAMAoGCCqGSM49BAMCA0gAMEUCIQDhL+sL9bcrvAVO3UvswA805EHujfL7iVDrbEuJfOSJoAIgBPKehtuILl9x/SJ5kxReiml1zkJqUB8nTy0UOfUNIIQ=", "nonce": "kauVuA==", "nonceSignature": "QHuLYArUCO2OZevP0rHc99g9RJp4O1dgsZuVpUdlA7zPWqCDhVQo9Mxr1uPS6GVyjZYo3YElIhHRV4Mv3wEJ3hGOaxK1gResup88QWDK1fL0", "tokenServiceProvider": "V", "vcardId": "v-123-f98b91af-77c9-4e78-a1fe-345268939401" } https://sandbox.api.visa.com/inapp/provisioning/cardData/applePayNo AuthorizationapiKeyxpayTokenxv2:1738829799:4d52a6449a6b1cb326da89a37fba5e6e38eaae756a050674d0f6071860f3d66d
Hey @Harris,
The "Token Validation Failed 401" error typically indicates that there is an issue with the authentication tokens or credentials being used when making requests to the Visa API. Here are some steps you can take to resolve this error when testing the Visa API in SOAPUI:
1. Verify X-Pay-Token Generation:
- Ensure that the `X-Pay-Token` is correctly generated according to the Visa API documentation. The token should be created using the shared secret and include the correct request parameters. Double-check the following formula:
```plaintext
X-Pay-Token = Base64(HMAC-SHA256(sharedSecret, timestamp + resourcePath + queryString + body))
```
- Ensure that the `timestamp` is in Unix epoch format and is within a valid time window when the request is made.
2. Check API Key:
- Make sure that the `apiKey` parameter in the query string matches the API key provided in your Visa Developer project.
3. Validate Resource Path and Query String:
- Ensure that the `resourcePath` and `queryString` used in generating the `X-Pay-Token` exactly match those in the actual request.
4. Ensure Correct Usage of HMAC-SHA256:
- Confirm that you are using the correct HMAC-SHA256 algorithm to compute the hash with the shared secret.
5. SOAPUI Configuration:
- Verify that SOAPUI is correctly configured to include the required headers. The `X-Pay-Token` should be included in the request headers along with the `Content-Type` and `Accept` headers set to `application/json`.
6. Double-check Timestamp:
- The `timestamp` used in token generation should not be too far in the past or future. A common issue is time synchronization, so ensure that your system clock is accurate.
Here's an example of how the headers might look like in SOAPUI:
```plaintext
POST https://sandbox.api.visa.com/your/resource/path
Headers:
Content-Type: application/json
Accept: application/json
X-Pay-Token: <generated-x-pay-token>
apiKey: <your-api-key>
```
7. Review Detailed Logs:
- Examine the detailed logs in SOAPUI to ensure that the request is correctly formed and that all parameters are as expected.
8. Consult Documentation and Examples:
- Refer to the Visa Developer documentation for any additional requirements or constraints. Reviewing sample requests and responses can also help identify discrepancies.
If you have followed all these steps and are still encountering the error, consider contacting Visa Developer support for more direct assistance. Provide them with the exact request details, including headers, body, and any error messages received.
By systematically verifying each of these areas, you should be able to identify and resolve the issue with your request.
Hi @DianaVisaPM ,
Thanks for your response and detailed steps.
I have thoroughly checked each of the suggested areas, including:
✅ X-Pay-Token Generation: The token is correctly generated using the formula mentioned in the Visa API documentation. The timestamp is in Unix epoch format and falls within a valid time window.
✅ API Key Validation: The apiKey parameter in the query string matches the API key from my Visa Developer project.
✅ Resource Path and Query String: The values used in token generation exactly match those in the request.
✅ HMAC-SHA256 Calculation: The hash is correctly computed using HMAC-SHA256 with the shared secret.
✅ SOAPUI Configuration: The request includes the necessary headers, with X-Pay-Token, Content-Type, and Accept all properly set to application/json.
✅ Timestamp Validation: The system clock is synchronized, and the timestamp is accurate.
✅ Logs Review: I have reviewed the detailed logs in SOAPUI, and the request parameters match the expected format.
However, despite verifying all these aspects, I am still receiving the same error response:
I have also provided the exact request and the Groovy script used for token generation, but the issue persists. Could you please assist in further diagnosing this issue? Is there a way to verify on the Visa API side if there are any logs or mismatches in the request validation?
Appreciate your support.
Hey @Harris,
It sounds like you've been very thorough in your troubleshooting process for the 401 "Token Validation Failed" error when testing the Visa API in SOAPUI. Given the steps you've already taken, here are a few additional suggestions and points to consider:
1. Check the Shared Secret: Make sure that the shared secret used for HMAC-SHA256 calculation is correct and matches the one provided in your Visa Developer project.
2. Encoding Issues: Ensure that there are no encoding issues. The X-Pay-Token generation might fail if there are any unexpected characters or encoding mismatches in the API key, shared secret, or any part of the token generation process.
3. Request Headers: Confirm that all required headers are included in the request. Besides `X-Pay-Token`, `Content-Type`, and `Accept`, ensure there are no additional headers required by the specific API you are calling.
4. Endpoint URL: Verify that the endpoint URL you are using is correct, including the correct base URL and resource path.
5. Request Body: Ensure that the request body (if applicable) is correctly formatted and matches the expected structure for the API endpoint.
6. Network Issues: Sometimes network issues, such as firewall settings or proxy configurations, can cause problems. Ensure that your network settings allow outbound HTTPS traffic to the Visa API endpoints.
7. Visa Developer Portal Logs: Check if the Visa Developer Portal provides any logs or insights for the API calls made from your project. Sometimes, the portal may provide additional details about failed requests.
8. SOAPUI Version: Ensure that you are using a compatible version of SOAPUI. Sometimes, older versions of SOAPUI may have issues with certain configurations or security protocols.
Here's an example Groovy script for generating the X-Pay-Token, in case you want to cross-check:
```groovy
// START
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec
import java.util.Base64
def generateXPayToken(apiKey, sharedSecret, resourcePath, queryString, requestBody) {
long timestamp = System.currentTimeMillis() / 1000
def preHashString = apiKey + timestamp + resourcePath + queryString + requestBody
def secret = new SecretKeySpec(sharedSecret.getBytes(), "HmacSHA256")
def mac = Mac.getInstance("HmacSHA256")
mac.init(secret)
def hash = mac.doFinal(preHashString.getBytes())
def xPayToken = "xv2:" + timestamp + ":" + Base64.getEncoder().encodeToString(hash)
return xPayToken
}
def apiKey = "YOUR_API_KEY"
def sharedSecret = "YOUR_SHARED_SECRET"
def resourcePath = "/v1/your/resource/path"
def queryString = "apikey=YOUR_API_KEY"
def requestBody = '{"example":"data"}'
def xPayToken = generateXPayToken(apiKey, sharedSecret, resourcePath, queryString, requestBody)
println "X-Pay-Token: " + xPayToken
// END
```